home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 May: Tool Chest / Dev.CD May 98 TC.toast / Tool Chest / Testing & Debugging / Mac OS Development Toolkit / Automation Essentials 2.3.0 / Host Automation Folder / Clouseau libs / Clouseau.Lib < prev    next >
Encoding:
Text File  |  1998-03-19  |  92.3 KB  |  2,613 lines  |  [TEXT/MPS ]

  1. #########################################################################
  2. #########################################################################
  3. ##                     Copyright © Apple Computer, Inc. 1990-1997
  4. ##                                All rights reserved
  5. #########################################################################
  6. #########################################################################
  7. #    
  8. #    Library:        Clouseau.lib
  9. #
  10. #    Version:        2.1.4
  11. #    
  12. #    Description:    Tasks that handle generic operations for high level
  13. #                    tests.  All tasks return true if executed successfully,
  14. #                    or false if an error occurs.
  15. #    
  16. #    Contains:
  17. #        await_presence()
  18. #        await_absence()
  19. #        balloon_await_presence()
  20. #        type_keys()
  21. #        select_descriptor()
  22. #        select_menuitem()
  23. #        move_mouse()
  24. #        select_popup()
  25. #        twitch()
  26. #        select_volume()
  27. #        find()
  28. #        close_all_windows()
  29. #        relocate_window()
  30. #        dismiss_dialog()
  31. #        select_window()
  32. #        close_window()
  33. #        key_eq()
  34. #        find()
  35. #        use_7_0_find()
  36. #        abort_script()
  37. #        AwaitText()
  38. #        LocateText()
  39. #        SetTextOptions()
  40. #        GetTextOptions()
  41. #        ValidateTextOptions()
  42. #    
  43. #    History:
  44. #        Some of these tasks were originally found in 007, written by EH
  45. #        and Alan Liu.  Some have had minor changes, many have had major changes. Some 
  46. #        still use the names of their predecessors but are entirely rewritten.
  47. #        Date:        By:            Changes:
  48. #        5/92        Jason Marsh    Clouseau 1.0 creation
  49. #        09/27/96    SBR/MSO/BRL    Updated copyright header
  50. #                                Use SPEC exception handling method (ExceptionHandling.lib)
  51. #        09/27/96    MSO            Added command and shift modifier
  52. #                                Used key_eq modifier 6 to improve chances of getting 7.0 find
  53. #        01/21/97    SBR            Deleted older exception code and comments.
  54. #        03/20/97    SBR            Added 'center of rect' action to move_mouse.
  55. #        04/07/97    SBR            Added wait() in await_presence/_absence for CHAT.
  56. #        04/10/97    SBR            Added AwaitText(), LocateText(), SetTextOptions(), 
  57. #                                GetTextOptions(), ValidateTextOptions().
  58. #        04/14/97      SBR            Added 'relToBounds' action to move_mouse.
  59. #        05/15/97      SBR            Added FindFile() (moved in from LaunchQuits.lib).
  60. #    
  61. #########################################################################
  62. #########################################################################
  63.  
  64. Libraries  
  65.     "ExceptionHandling.lib"
  66.     ,"Report.lib"
  67.     ,"VUAid.lib"
  68.     ;
  69.  
  70. #########################################################################
  71. #    task        await_presence(feature_desc, time_limit, persistence, exact, v_level)
  72. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  73. #    Description:    Wait for the feature with descriptor {feature_desc} to
  74. #                    appear. If more than {time_limit} seconds pass, then
  75. #                    return a false (error) result. If the feature is found,
  76. #                    return a true result. If a non-zero {persistence} is
  77. #                    specified, wait for the feature to be present for
  78. #                    {persistence} seconds.  Use this library call instead
  79. #                    of just wait() whenever possible because it's more robust.
  80. #    Parameters:        feature_desc:    descriptor of thing to look for
  81. #                    time_limit:        how long to wait in seconds
  82. #                    persistence:    how long to ensure that the object
  83. #                                    stays around.
  84. #                    exact:            whether to perform an EXACT match
  85. #                    v_level:        verbosity level for log output
  86. #                                    Pass a v_level of 6 to silence errors
  87. #                                    and not have them add up for the test summary
  88. #    Returns:        success:    true
  89. #                    failure:    false
  90. #    Examples:        if (await_presence([statictext t: "No matching items were found."], 20) = error)
  91. #                            #Wait up to 20 seconds for a dialog that says
  92. #                            # "No matching items were found." to appear.
  93. #                      return(incomplete);
  94. #                             #If it does not appear, then return 'incomplete'.
  95. #                    else    #otherwise call the task  "Open_Object"
  96. #                           Open_Object('My Folder');
  97. #    Assumptions:    We assume that {persistence} will be less than 3600
  98. #                    (one hour) and that the {time_limit} will be less than
  99. #                    86400 (a day).
  100. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  101. #    History:
  102. #        7/25/90 Alan Liu        Creation as part of ApplicationLib.vu for 007
  103. #        3/4/92  Jason Marsh        Incorporation into Clouseau.Lib.
  104. #        06/12/93    SBR            Modified to use Errors.lib
  105. #        12/15/93    JDL            Corrected return information in the description
  106. #                                area of the header
  107. #        05/25/94    SBR            Modified to use _MatchBoolean instead of _Match
  108. #        06/07/94    SBR            Modified to use timed_out() instead of timer()
  109. #        04/07/97    SBR            Added wait() to reduce network traffic for CHAT.
  110. #########################################################################
  111. task    await_presence(feature_desc, time_limit := 10, persistence := 0,
  112.             exact := true, v_level := 5)
  113. begin
  114.     wait_end := get_end_time(time_limit);    # Reset the time limit timer
  115.     persist_end := 0;                        # Reset the persistence timer
  116.  
  117.     while true
  118.     begin
  119.         found := _MatchBoolean(feature_desc, exact);
  120.         if not found
  121.             persist_end := 0;                # No match; reset persistence
  122.         else 
  123.         begin
  124.             if not persistence
  125.                 return true;
  126.             else 
  127.             begin
  128.                 if not persist_end
  129.                     persist_end := get_end_time(persistence);
  130.                 if timed_out(persist_end)
  131.                     return true;
  132.             end;
  133.         end;
  134.  
  135.         if timed_out(wait_end)
  136.         begin
  137.             RIncomplete("await_presence: Descriptor did not appear, time limit = {time_limit}",v_level);
  138.             RStatus("∂t∂t{feature_desc}", v_level);
  139.             RDumpState(,v_level);
  140.             return false;
  141.         end;
  142.         
  143.         # Wait a bit, to reduce traffic when VU is running on the campus net.
  144.         wait(0,0,0,250);
  145.     end;
  146. end;
  147.  
  148. #########################################################################
  149. #    task        await_absence(feature_desc, time_limit, persistence, exact, v_level)
  150. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  151. #    Description:    Wait for the feature with descriptor {feature_desc} to
  152. #                    disappear. If more than {time_limit} seconds pass, then
  153. #                    return a false (error) result. If the feature is gone,
  154. #                    return a true result. If a non-zero {persistence} is
  155. #                    specified, wait for the feature to be absent for
  156. #                    {persistence} seconds.  Use this library call instead
  157. #                    of just wait() whenever possible because it's more robust.
  158. #    Parameters:        feature_desc:    descriptor of thing to look for
  159. #                    time_limit:        how long to wait in seconds
  160. #                    persistence:    how long to ensure that the object
  161. #                                    stays around.
  162. #                    exact:            whether to perform an EXACT match
  163. #                    v_level:        verbosity level for log output
  164. #                                    Pass a v_level of 6 to silence errors
  165. #                                    and not have them add up for the test summary
  166. #    Returns:        success:    true
  167. #                    failure:    false
  168. #    Examples:        if (await_absence ([window t:'Find' o:1], 300) = error)    
  169. #                            #Wait up to 300 seconds for the dialog to disappear.
  170. #                    return(incomplete);
  171. #                            #If it does not appear, then return 'incomplete'.
  172. #                    else    #otherwise  call the task  "Drag_Trash".
  173. #                       DragTrash('My Folder', true);
  174. #    Assumptions:    We assume that {persistence} will be less than 3600
  175. #                    (one hour) and that the {time_limit} will be less than
  176. #                    86400 (a day).
  177. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  178. #    History:
  179. #        7/25/90 Alan Liu        Creation as part of ApplicationLib.vu for 007
  180. #        3/4/92  Jason Marsh        Incorporation into Clouseau.Lib.
  181. #        06/12/93    SBR            Modified to use Errors.lib
  182. #        12/15/93    JDL            Corrected return information in the description
  183. #                                area of the header
  184. #        05/25/94    SBR            Modified to use _MatchBoolean instead of _Match
  185. #        06/07/94    SBR            Modified to use timed_out() instead of timer()
  186. #        09/27/96    BRL/MSO        Added SPEC exception handling
  187. #        04/07/97    SBR            Added wait() to reduce network traffic for CHAT.
  188. #########################################################################
  189. task    await_absence(feature_desc, time_limit := 10, persistence := 0,
  190.             exact := true, v_level := 5)
  191. begin
  192.     wait_end := get_end_time(time_limit);    # Reset the time limit timer
  193.     persist_end := 0;                        # Reset the persistence timer
  194.  
  195.     while true
  196.     begin
  197.         found := _MatchBoolean(feature_desc, exact);
  198.         if found
  199.             persist_end := 0;                # Still there; reset persistence
  200.         else 
  201.         begin
  202.             if not persistence
  203.                 return true;
  204.             else 
  205.             begin
  206.                 if not persist_end
  207.                     persist_end := get_end_time(persistence);
  208.                 if timed_out(persist_end)
  209.                     return true;
  210.             end;
  211.         end;
  212.  
  213.         if timed_out(wait_end)
  214.         begin
  215.             RIncomplete("await_absence: Descriptor did not disappear, time limit = {time_limit}",v_level);
  216.             RStatus("∂t∂t{feature_desc}", v_level);
  217.             RDumpState(,v_level);
  218.             return false;
  219.         end;
  220.         
  221.         # Wait a bit, to reduce traffic when VU is running on the campus net.
  222.         wait(0,0,0,250);
  223.     end;
  224. end;
  225.  
  226.  
  227. #########################################################################
  228. #    task        balloon_await_presence(time_limit, persistence, exact, v_level)
  229. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  230. #    Description:    Wait for the balloon to appear. If more than {time_limit} seconds
  231. #                    pass, then return a false (error) result. If the feature is found,
  232. #                    return a true result. If a non-zero {persistence} is
  233. #                    specified, wait for the feature to be present for
  234. #                    {persistence} seconds.  Use this library call instead
  235. #                    of just wait() whenever possible because it's more robust.
  236. #    Parameters:        time_limit:        how long to wait in seconds
  237. #                    persistence:    how long to ensure that the object
  238. #                                    stays around.
  239. #                    exact:            whether to perform an EXACT match
  240. #                    v_level:        verbosity level for log output
  241. #                                    Pass a v_level of 6 to silence errors
  242. #                                    and not have them add up for the test summary
  243. #                    expected:        list of correct checksums.
  244. #    Returns:        success:    true
  245. #                    failure:    false
  246. #    Examples:        await_presence(20) 
  247. #                            #Wait up to 20 seconds for a balloon to appear.
  248. #    Assumptions:    We assume that {persistence} will be less than 3600
  249. #                    (one hour) and that the {time_limit} will be less than
  250. #                    86400 (a day).
  251. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  252. #    History:
  253. #        07/25/90 Alan Liu                Creation as part of ApplicationLib.vu for 007
  254. #        05/10/95 Geraldine O'Sullivan    Modified to wait for correct balloon to appear.
  255. #########################################################################
  256. task    balloon_await_presence(time_limit := 10, persistence := 0, v_level := 5, expected)
  257. begin
  258.     wait_end := get_end_time(time_limit);    # Reset the time limit timer
  259.     persist_end := 0;                        # Reset the persistence timer
  260.  
  261.     while true
  262.     begin
  263.         actual:= VUAid("Balloon");
  264.         if typeOf(expected) = 'list'
  265.             success := isMember(actual, expected);
  266.         else
  267.             success := (actual = expected);
  268.  
  269.         if not success
  270.             persist_end := 0;                # No match; reset persistence
  271.         else
  272.         begin
  273.             if not persistence
  274.                 return true;
  275.             else 
  276.             begin
  277.                 if not persist_end
  278.                     persist_end := get_end_time(persistence);
  279.                 if timed_out(persist_end)
  280.                     return true;
  281.             end;
  282.     
  283.             if timed_out(wait_end)
  284.                 return false;
  285.         end;
  286.     end;
  287. end;
  288.  
  289.  
  290. #########################################################################
  291. #    task                    type_keys(key_list, v_level)
  292. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  293. #    Description:    Performs the same function that type k:key_list would,
  294. #                    with the addition of a few new symbols:
  295. #                        'down'         causes the following key to be pressed
  296. #                        'up'        causes the following key to be released
  297. #                        'latch'        causes the following key to be pressed
  298. #                                    only for a single keystroke.
  299. #                        'waitx'     wait 'x' seconds (9 maximum)
  300. #    Parameters:        key_list:        list of keyboard actions to perform, may
  301. #                                    contain any 'type' command input, and the
  302. #                                    keywords listed above.
  303. #                    v_level:        verbosity level for log output
  304. #    Returns:        true
  305. #    Examples:        type_keys({'down', shiftKey, 'a', 'bc', 'latch', optionKey,
  306. #                                'qu', 'x', 'up', shiftKey, 'p', 'down', shiftKey, 'x'});
  307. #                        # Causes the string 'ABCŒ¨pX' to be typed.
  308. #    Assumptions:    Multiple latched keys may be specified by latching one
  309. #                    after the other: {'latch', shiftKey, 'latch', commandKey, 'A'}
  310. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  311. #    History:
  312. #        7/25/90 Alan Liu        Creation as part of ApplicationLib.vu for 007
  313. #        3/4/92  Jason Marsh        Incorporation into Clouseau.Lib.
  314. #        12/15/93    JDL            Added documentation of wait function to header
  315. #        09/27/96  BRL/MSO        Added SPEC exception handling
  316. #########################################################################
  317. task    type_keys(key_list := {}, v_level:= 5)
  318. begin
  319.     latchList := {};        (*These keys have been latched*)
  320.     mode := 'idle';         (*Mode can be 'idle', 'down', 'up', or 'latch'*)
  321.     if RXStatus (v_level) println "type_keys: typing ", key_list;
  322.     
  323.     for i := 1 to card key_list
  324.     begin
  325.         key := key_list[i];
  326.         
  327.         if key ~= /wait≈/
  328.             wait(strToNum(key[5]));
  329.         else 
  330.         begin
  331.             if (mode = 'idle')
  332.             begin
  333.                 if (key = 'down' or key = 'up' or key = 'latch')
  334.                     mode := key;
  335.                 else 
  336.                 begin
  337.                     _Type({key});
  338.                     if latchList 
  339.                     begin
  340.                         _ReleaseKey(latchList);
  341.                         latchList := {};
  342.                     end;
  343.                 end;
  344.             end;
  345.             else if (mode = 'latch' or mode = 'down') 
  346.             begin
  347.                 _PressKey({key});
  348.                 if (mode = 'latch') 
  349.                     latchList := insert(key, 1 + card latchList, latchList);
  350.                 mode := 'idle';
  351.             end;
  352.             else if (mode = 'up') 
  353.             begin
  354.                 _ReleaseKey({key});
  355.                 mode := 'idle';
  356.             end;
  357.         end;
  358.     end;
  359.     
  360.     if latchList 
  361.         _ReleaseKey(latchList);
  362.     return true;                #always returns true
  363. end;
  364.  
  365.  
  366. #########################################################################
  367. #    task                    select_descriptor(itemDesc, timeLimit, v_level)
  368. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  369. #    Description:    Select an item by its descriptor.  Possible descriptors
  370. #                    currently are: windows, check boxes, buttons, radio
  371. #                    buttons, menus, and menu items.  If the descriptor is
  372. #                    a checkbox it checks to see if its setting changed.
  373. #                    If it is a radio button it check to see if it is on
  374. #                    after it was selected.
  375. #    Parameters:        itemDesc:        a descriptor of the item you want to select
  376. #                    timeLimit:        if <> 0 call await_presence with this time_limit
  377. #                    v_level:        verbosity level for log output
  378. #    Returns:        success: true, failure: false
  379. #    Examples:        select_descriptor([button t:'OK']);
  380. #    Assumptions:    None
  381. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  382. #    History:
  383. #        2/27/91        EH        Creation as part of SelectLib.vu for 007.
  384. #        3/4/92        Jason Marsh        Incorporated into Clouseau.Lib.
  385. #        05/27/93    SBR        Added v_level to 'Unable to find' errors
  386. #        06/12/93      SBR        Modified to use Errors.lib
  387. #########################################################################
  388. task    select_descriptor(itemDesc := '', timeLimit := 0, v_level := 5)
  389. begin
  390.     error := false;
  391.     noErr := true;
  392.     
  393.     ## See if we got anything
  394.     if not (itemDesc)
  395.         return error;
  396.         
  397.     ## Wait for item to appear
  398.     if timeLimit <> 0 
  399.     begin
  400.         if not (await_presence(itemDesc,timeLimit)) 
  401.         begin
  402.             if RXIncomplete(v_level)
  403.                 println "select_descriptor: Unable to find '",itemDesc,"'";
  404.             RDumpState(descType(itemDesc),v_level);    #Dump diagnostic info
  405.             return error;
  406.         end;
  407.     end;
  408.     else 
  409.     begin
  410.         found := _Match(itemDesc,true);                #exact match
  411.         if not found 
  412.         begin
  413.             if RXIncomplete(v_level)
  414.                 println "select_descriptor: Unable to find '",itemDesc,"'";
  415.             RDumpState(descType(itemDesc),v_level);    #Dump diagnostic info
  416.             return error;
  417.         end;
  418.     end;
  419.     
  420.     beforeDesc := found;                        #save descriptor's state before selecting
  421.     descriptorType := descType(itemDesc);
  422.             
  423.     ## Select item
  424.     if descriptorType = 'window'                 #check for the Desktop "window"
  425.         if beforeDesc.r = {0,0,0,0}             #RIncomplete always returns false
  426.             return RIncomplete("select_descriptor: no windows are open to select",v_level);
  427.             
  428.             
  429.     selected := _SelectBoolean(itemDesc, true);
  430.     if not selected
  431.         return RIncomplete("select_descriptor: Error while selecting {itemDesc}",v_level);
  432.         
  433.     if (descriptorType = 'radiobutton' or descriptorType = 'checkbox') 
  434.     begin
  435.         afterDesc := _Match(itemDesc, true);
  436.         if not afterDesc
  437.             return RIncomplete("select_descriptor: Error verifying {descriptorType}, it was not found",v_level);
  438.     
  439.         ## Now check to see if what we did worked only for checkboxes and
  440.         ## radiobuttons.  Do not check when selecting menus, menu items,
  441.         ## buttons, and windows.
  442.         if (descriptorType = 'checkbox') 
  443.         begin
  444.             if (beforeDesc.s = afterDesc.s)
  445.                 if RXIncomplete(1)
  446.                     println "select_descriptor: Check box titled '",afterDesc.t,"' did not change it's setting";
  447.         end;
  448.         else if (descriptorType = 'radiobutton') 
  449.         begin
  450.             if not (afterDesc.s = { 1,1 })
  451.                 if RXIncomplete(1)
  452.                     println "select_descriptor: Radio button titled '",afterDesc.t,"' did not become set";
  453.         end;
  454.     end;
  455.     if RXStatus(v_level) 
  456.         println "select_descriptor: ", itemDesc , " selected";
  457.     return noErr;
  458. end;
  459.  
  460. (*
  461. #########################################################################
  462. #    task                    select_descriptor_CP(itemDesc, timeLimit, v_level)
  463. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  464. #    Description:    Select an item by its descriptor.  Possible descriptors
  465. #                    currently are: windows, check boxes, buttons, radio
  466. #                    buttons, menus, and menu items.  If the descriptor is
  467. #                    a checkbox it checks to see if its setting changed.
  468. #                    If it is a radio button it check to see if it is on
  469. #                    after it was selected.
  470. #            NOTE:    This task is identical to select_descriptor() in Clouseau.lib, 
  471. #                    except it checks if the front window's title is in the list of
  472. #                    control panels with the dreaded "-89 offset". If the window is
  473. #                    one of the bad ones, and the descriptor is a contentItem, the
  474. #                    task adds 89 horizontally and does a manual click on the item, 
  475. #                    otherwise it acts normally. This task will become obsolete when 
  476. #                    we switch to VU 2.1, which corrects the -89 offset by itself.
  477. #            NOTE:    This task does not fix the problem in VU 2.0.1 of items which
  478. #                    end up outside the content region after being "moved" by -89.
  479. #                    In these cases VU does not allow access to these descriptors
  480. #                    by match or select, so VUAid has to verify the setting.
  481. #    Parameters:        itemDesc:        a descriptor of the item you want to select
  482. #                    timeLimit:        if <> 0 call await_presence with this time_limit
  483. #                    v_level:        verbosity level for log output
  484. #    Returns:        success: true, failure: false
  485. #    Examples:        select_descriptor([button t:'OK']);
  486. #    Assumptions:    None
  487. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  488. #    History:
  489. #        2/27/91        EH        Creation as part of SelectLib.vu for 007.
  490. #        3/4/92        Jason Marsh        Incorporated into Clouseau.Lib.
  491. #        05/27/93    SBR        Added v_level to 'Unable to find' errors
  492. #        06/12/93      SBR        Modified to use Errors.lib
  493. #        06/14/94      SBR        Added -89 offset correction
  494. #        09/27/96      BRL/MSO    Added SPEC exception handling
  495. #########################################################################
  496. #task    select_descriptor_CP(itemDesc := '', timeLimit := 0, v_level := 5)
  497. begin
  498.     error := false;
  499.     noErr := true;
  500.     
  501.     ## See if we got anything
  502.     if not (itemDesc)
  503.         return error;
  504.         
  505.     ## Wait for item to appear
  506.     if timeLimit <> 0 
  507.     begin
  508.         if not (await_presence(itemDesc,timeLimit)) 
  509.         begin
  510.             if RXIncomplete(v_level)
  511.                 println "select_descriptor: Unable to find '",itemDesc,"'";
  512.             RDumpState(descType(itemDesc),v_level);    #Dump diagnostic info
  513.             return error;
  514.         end;
  515.     end;
  516.     else 
  517.     begin
  518.         found := _Match(*Boolean*)(itemDesc,true);                #exact match
  519.         if not found 
  520.         begin
  521.             if RXIncomplete(v_level)
  522.                 println "select_descriptor: Unable to find '",itemDesc,"'";
  523.             RDumpState(descType(itemDesc),v_level);    #Dump diagnostic info
  524.             return error;
  525.         end;
  526.     end;
  527.     
  528.     beforeDesc := found;                        #save descriptor's state before selecting
  529.     descriptorType := descType(itemDesc);
  530.             
  531.     ## Select item
  532.     if descriptorType = 'window'                 #check for the Desktop "window"
  533.         if beforeDesc.r = {0,0,0,0}             #RIncomplete always returns false
  534.             return RIncomplete("select_descriptor: no windows are open to select",v_level);
  535.             
  536.             
  537.     selected := _SelectBoolean(itemDesc, true);
  538.     if not selected
  539.         return RIncomplete("select_descriptor: Error while selecting {itemDesc}",v_level);
  540.         
  541.     if (descriptorType = 'radiobutton' or descriptorType = 'checkbox') 
  542.     begin
  543.         afterDesc := _Match(*Boolean*)(itemDesc, true);
  544.         if not afterDesc
  545.             return RIncomplete("select_descriptor: Error verifying {descriptorType}, it was not found",v_level);
  546.     
  547.         ## Now check to see if what we did worked only for checkboxes and
  548.         ## radiobuttons.  Do not check when selecting menus, menu items,
  549.         ## buttons, and windows.
  550.         if (descriptorType = 'checkbox') 
  551.         begin
  552.             if (beforeDesc.s = afterDesc.s)
  553.                 if RXIncomplete(1)
  554.                     println "select_descriptor: Check box titled '",afterDesc.t,"' did not change it's setting";
  555.         end;
  556.         else if (descriptorType = 'radiobutton') 
  557.         begin
  558.             if not (afterDesc.s = { 1,1 })
  559.                 if RXIncomplete(1)
  560.                     println "select_descriptor: Radio button titled '",afterDesc.t,"' did not become set";
  561.         end;
  562.     end;
  563.     if RXStatus(v_level) 
  564.         println "select_descriptor: ", itemDesc , " selected";
  565.     return noErr;
  566. end;
  567. *)
  568.  
  569. #########################################################################
  570. #    task            select_menuItem(menuName1, menuName2, menuName3, keyEquiv, v_level)
  571. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  572. #    Description:    Selects a menu item by its name. Each menuName parameter can be a 
  573. #                    string or regular expression representing the title, or an integer 
  574. #                    denoting the ordinal. The menuItem descriptor built from these 
  575. #                    parameters is matched exactly (with !) and checked for enablement, 
  576. #                    then it is selected exactly. Exact match and select are much faster
  577. #                    than inexact. If you want to specify a partial menuName, use the 
  578. #                    wildcard (?≈) characters in a regular expression. (see example)
  579. #    Parameters:        menuName1:        Menu item to be selected.
  580. #                    menuName2:        Menu name if non-hier menu and
  581. #                                     Level 2 menu item if hier menu.
  582. #                    menuName3:        Menu name if hier menu.
  583. #                    keyEquiv:        true: use command key equivalent if available
  584. #                                    false: always select the menu item
  585. #                    v_level:        verbosity level for log output
  586. #    Returns:        true for successful selection, false for unsuccessful.
  587. #    Examples:        select_menuitem("Save", "File");
  588. #                    select_menuitem("Scrapbook", 1);
  589. #                    select_menuitem(/≈h≈w b≈ll≈/);    (this selects Show Ballons)
  590. #    Assumptions:    Do not have to pass 'menuName2' or 'menuName3'
  591. #                    as a parameter.  In that case, default value, "",
  592. #                    will be used.
  593. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  594. #    History:
  595. #        4/4/90        SL        Created
  596. #        3/27/92     JM        modified from Controls.lib and included in Clouseau
  597. #        04/02/93     SBR        Added select by ordinality
  598. #        04/02/93     SBR        Fixed selecting sub-menuItems using only menuID1 
  599. #        04/02/93     SBR        More descriptive output when verbose 
  600. #        06/12/93      SBR        Modified to use Errors.lib except for VU bug fix
  601. #        09/27/96      BRL/MSO    Added SPEC exception handling
  602. #########################################################################
  603. task select_menuItem(menuID1, menuID2 := "", menuID3 := "", keyEquiv := false, v_level := 4) 
  604. begin
  605.     if (typeOf(keyEquiv) = 'integer') and (v_level = 5) 
  606.     begin
  607.         if isUndefined(global __gBadSMI__) 
  608.         begin
  609.             RStatus('The select_menuItem parameter list has changed. Your script should still work.',1);
  610.             RStatus('This message will occur only once per run.',1);
  611.             __gBadSMI__ := true;            #only print the message once;
  612.             v_level := 1;                    #be verbose to help locate this call
  613.         end;
  614.         else 
  615.             v_level := keyEquiv;            #assume the integer was a valid v_level 
  616.             
  617.         keyEquiv := false;
  618.     end;
  619.     
  620.     if typeOf(menuID1) <> 'integer' 
  621.     begin
  622.         if menuID2 
  623.         begin
  624.             if menuID3 
  625.                 if typeOf(menuID2) <> 'integer'
  626.                     ourMenuItem := _Match([menuItem t:menuID1 m:[menuItem t:menuID2 m:menuID3]], true);
  627.                 else 
  628.                     ourMenuItem := _Match([menuItem t:menuID1 m:[menuItem o:menuID2 m:menuID3]], true);
  629.             else 
  630.                 ourMenuItem := _Match([menuItem t:menuID1 m:menuID2], true);
  631.         end;
  632.         else 
  633.             ourMenuItem := _Match([menuItem t:menuID1], true);
  634.     end;
  635.       else begin
  636.         if menuID2 
  637.         begin
  638.             if menuID3 
  639.                 if typeOf(menuID2) <> 'integer'
  640.                     ourMenuItem := _Match([menuItem o:menuID1 m:[menuItem t:menuID2 m:menuID3]], true);
  641.                 else 
  642.                     ourMenuItem := _Match([menuItem o:menuID1 m:[menuItem o:menuID2 m:menuID3]], true);
  643.             else 
  644.                 ourMenuItem := _Match([menuItem o:menuID1 m:menuID2], true);
  645.         end;
  646.         else 
  647.             ourMenuItem := _Match([menuItem o:menuID1], true);
  648.     end;
  649.     
  650.     keyString := '';
  651.     mString := '';
  652.     theError := '';
  653.     if not ourMenuItem theError := 'the match failed';
  654.     else omi := ourMenuItem;        # a shorter name
  655.     if (omi)                          # menu item exists and there was no error
  656.     begin
  657.         isHierarchical := descType(omi.m) = 'menuItem';
  658.         if isHierarchical 
  659.         begin
  660.             ########################################################
  661.             ##### This 2nd match is necessary because of a VU bug - VU "loses" the top menu when you
  662.             ##### put a hierarchical menu into a variable. Then, selecting and matching take much
  663.             ##### more time for hierarchical menus (e.g. 5-9 seconds per). Bug exists in 
  664.             ##### VU 2.0.1 and previous versions. The only other alternative is to select without
  665.             ##### matching first, but this bypasses all the nice error detection.
  666.             ##### To save time after bug is fixed, simply remove or comment out this section
  667.             _menuBugExists__ := true;
  668.             if not menuID3
  669.             begin
  670.                 try 
  671.                     match [menuItem t:omi.t o:omi.o m:[menuItem t:omi.m.t o:omi.m.o m:[menu t:?t1 o:?t2]]]!;
  672.                 catch theError
  673.                     ExceptionDispatcher(theError,,{"match 1  in select_menuItem", {menuID1, menuID2, menuID3, keyEquiv, v_level}});
  674.             end;
  675.             else if typeOf(menuID3) = 'string' 
  676.             begin
  677.                 t1 := menuID3;
  678.                 try 
  679.                     match [menuItem t:omi.t o:omi.o m:[menuItem t:omi.m.t o:omi.m.o m:[menu t:t1 o:?t2]]]!;
  680.                 catch theError
  681.                     ExceptionDispatcher(theError,,{"match 2  in select_menuItem", {menuID1, menuID2, menuID3, keyEquiv, v_level}});
  682.             end;
  683.             else 
  684.             begin
  685.                 t2 := menuID3;
  686.                 try 
  687.                     match [menuItem t:omi.t o:omi.o m:[menuItem t:omi.m.t o:omi.m.o m:[menu t:?t1 o:t2]]]!;
  688.                 catch theError
  689.                     ExceptionDispatcher(theError,,{"match 3  in select_menuItem", {menuID1, menuID2, menuID3, keyEquiv, v_level}});
  690.             end;
  691.             if temp[1] 
  692.                 theError := temp[2];
  693.             
  694.             if _menuBugExists__
  695.                 hierMenu := [menu t:t1 o:t2];    # execute this statement before bug is fixed
  696.             else
  697.             ########################################################
  698.             hierMenu := omi.m.m;                # execute this statement after bug is fixed
  699.         end;
  700.         
  701.         if theError;
  702.         else if not (omi.e)    
  703.             theError := "it is disabled";
  704.         else 
  705.         begin
  706.             if keyEquiv 
  707.             begin
  708.                 theChar := omi.k;
  709.                 if theChar                         # command key equivalent?
  710.                 begin
  711.                     if theChar ~= /[A-Z]/             # do not press shift key for normal cmd-key
  712.                         theChar := codeToCharacter(32 + characterToCode(theChar));
  713.                     key_eq(theChar);
  714.                     keyString := ", by its key equivalent";
  715.                 end;
  716.                 else 
  717.                 begin
  718.                     keyString := ", no VU-visible key equivalent";
  719.                     keyEquiv := false;
  720.                 end;
  721.             end;    
  722.             if not keyEquiv                     # if not select normally
  723.             begin
  724.                 if isHierarchical
  725.                     temp := _SelectBoolean(
  726.                                 [menuItem t:omi.t o:omi.o m:[menuItem t:omi.m.t o:omi.m.o m:hierMenu.t]],true);
  727.                 else 
  728.                     temp := _SelectBoolean([menuItem t:omi.t o:omi.o m:[menu t:omi.m.t o:omi.m.o]],true);
  729.                 if not temp 
  730.                     theError := 'VU could not select it';
  731.             end;
  732.         end;
  733.     end;
  734.     
  735.     if R_BeVerbose(v_level)                     # skip fancy reporting normally
  736.     begin
  737.         if not omi                                 # menu item does not exist 
  738.         begin
  739.             if menuID3 
  740.                 mString := "{menuID1} from menu item {menuID2} from menu {menuID3}";
  741.             else if menuID2 
  742.                 mString := "{menuID1} from menu {menuID2}";
  743.             else 
  744.                 mString := "{menuID1}";
  745.             theError := "it does not exist";
  746.         end;
  747.         else 
  748.         begin
  749.             menu1Ord := omi.o;
  750.             menu2Ord := omi.m.o;
  751.             if isHierarchical
  752.             begin
  753.                 menu3Ord := hierMenu.o;
  754.                 mString := "'"+omi.t+"'" + " ({menu1Ord})" + " from menu item " + "'"+omi.m.t+"'" + 
  755.                     " ({menu2Ord})" + " from the " + "'"+hierMenu.t+"'" + " menu" + " ({menu3Ord})";
  756.             end;
  757.             else 
  758.                 mString := "'"+omi.t+"'" + " ({menu1Ord})" + " from the " + "'"+omi.m.t+"'" + " menu"
  759.                     + " ({menu2Ord})";
  760.         end;
  761.         if theError
  762.             RIncomplete("select_menuItem: Failed to select {mString}{keyString} because {theError}",v_level);
  763.         else 
  764.             RStatus("select_menuItem: Selected {mString}{keyString}" ,v_level);
  765.     end;
  766.     if theError 
  767.         return false;
  768.     else 
  769.         return true;
  770. end; # select_MenuItem()
  771.  
  772.  
  773.  
  774. #########################################################################
  775. #    task            move_mouse(action_list, waitState, v_level)
  776. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  777. #    Description:    This task is a mouse equivalent to type_keys.  Pass it
  778. #                    an action_list (see example below) to execute, waiting
  779. #                    between each action for a waitState second.  Warning:
  780. #                    this routine  automatically releases the mouse for you
  781. #                    if you leave it down, and it does release the ShiftKey
  782. #                    if you leave it down.  This routine runs very fast, and
  783. #                    may require a waitState and/or 'waitx' statements to 
  784. #                    produce solid results.
  785. #    Parameters:        actionList:        List of possible actions: 
  786. #                        {X,Y} - move to location
  787. #                        {l,t,r,b} - move to center of rectangle
  788. #                        'relative' - relative to last click mode
  789. #                        'relToWindow' or 'rtw' - relative to window rect mode
  790. #                        'relToBounds' or 'rtb' - relative to window bounds mode
  791. #                        'absolute' - absolute mode
  792. #                        'click' - do a mouse click
  793. #                        'doubleClick' - do a doubleClick
  794. #                        'down' - do a pressMouse 
  795. #                        'up'- do a releaseMouse
  796. #                        'press' - press down the following key
  797. #                        'release' - release the following key
  798. #                        'waitx' - wait 'x' seconds (9 maximum)
  799. #                    waitState:        How long to pause between individual
  800. #                                    actions.
  801. #                    v_level:        verbosity level for log output
  802. #    Returns:        true if you sent it a valid list, false if not
  803. #    Examples:                #this example will select the first and fourth items
  804. #                            #in a non-icon window and drag them both to the trash.
  805. #                    scr := match[screen];        #find the trash -- hopefully!#
  806. #                    trshX := scr.r[3] - 48; trshY := scr.r[4] - 43;
  807. #                    move_mouse({ { 25,50 },'click','press', ShiftKey, { 25,100 },
  808. #                        'click','release', ShiftKey, 'absolute', 'down', {trshX,trshY}});    
  809. #    Assumptions:    None
  810. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  811. #    History:
  812. #        03/04/92    Jason Marsh        Created
  813. #        07/12/94    SBR                Fixed bug where we can leave keys pressed. It had
  814. #                                    released some modifiers but not all pressed keys.
  815. #        09/27/96      BRL/MSO            Added SPEC exception handling
  816. #        03/20/97      SBR                Added {l,t,r,b} (move to center of rect) action
  817. #        04/14/97      SBR                Added 'relToBounds' action
  818. #########################################################################
  819. task    move_mouse(action_list := {}, waitState := 0, v_level:= 5)
  820. begin
  821.     mode := 'relToWindow';         #Mode can be 'relative', 'relToWindow',
  822.                                     # 'relToBounds' or 'absolute'
  823.     if RXStatus (v_level)
  824.         println "move_mouse: doing ", action_list;
  825.     
  826.     # 07/12/94 SBR: new code with keysPressed is to ensure all pressed keys are released
  827.     keysPressed := {};
  828.     
  829.     for i := 1 to card action_list
  830.     begin
  831.         action := action_list[i];
  832.         
  833.         if typeOf(action) = 'list'                 # If it's coordinates, move there
  834.         begin
  835.             if card action = 4
  836.             begin
  837.                 # Calculate the center point of a 4-item rectangle.
  838.                 action := {(action[1] + action[3])/2, (action[2] + action[4])/2};                
  839.             end;
  840.             
  841.             if (mode = 'relToWindow' or mode = 'rtw') 
  842.             begin
  843.                 if IsUndefined(windowRect)
  844.                 begin
  845.                     try 
  846.                         match [window o:1 r:?windowRect]!;
  847.                     catch theError
  848.                         ExceptionDispatcher(theError,,{"match 1 in move_mouse()", 
  849.                                                 {action_list, waitState, v_level}});
  850.                 end;
  851.                 _Move('a',{ windowRect[1] + action[1], windowRect[2] + action[2] });
  852.             end;
  853.             else if (mode = 'relToBounds' or mode = 'rtb') 
  854.             begin
  855.                 if IsUndefined(windowBounds)
  856.                 begin
  857.                     try 
  858.                         match [window o:1 b:?windowBounds]!;
  859.                     catch theError
  860.                         ExceptionDispatcher(theError,,{"match 2 in move_mouse()", 
  861.                                                 {action_list, waitState, v_level}});
  862.                 end;
  863.                 _Move('a',{ windowBounds[1] + action[1], windowBounds[2] + action[2] });
  864.             end;
  865.             else if (mode = 'absolute')
  866.                 _Move('a',{ action[1], action[2]});
  867.             else 
  868.                 _Move('r',{ action[1], action[2]});
  869.         end;
  870.         else if action = 'click'
  871.             _Click();
  872.         else if action = 'doubleClick'
  873.             _DoubleClick();
  874.         else if isMember(action, { 'relative','absolute','rtw','relToWindow',
  875.                                         'rtb','relToBounds'})
  876.             mode := action;
  877.         else if action = 'down'
  878.             _PressMouse();
  879.         else if action = 'up'
  880.             _ReleaseMouse();
  881.         else if action = 'press' 
  882.         begin
  883.             i:= i+1;
  884.             theKey := action_list[i];
  885.             _PressKey({theKey});
  886.             keysPressed := keysPressed + {theKey};
  887.         end;
  888.         else if action = 'release' 
  889.         begin
  890.             i:= i+1;
  891.             theKey := action_list[i];
  892.             
  893.             _ReleaseKey({theKey});
  894.             releasedIndex := isMember(theKey, keysPressed);
  895.             if releasedIndex 
  896.                 keysPressed := remove(releasedIndex, keysPressed);
  897.         end;
  898.         else if action ~= /wait≈/
  899.             wait(strToNum(action[5]));
  900.         else 
  901.         begin
  902.             _ReleaseMouse();            # release possible pressed items before returning
  903.             for each theKey in keysPressed        
  904.                 _ReleaseKey({theKey});
  905.             return RIncomplete("move_mouse: incorrect command: {action_list}");
  906.         end;
  907.         if waitState > 0 
  908.             wait(waitState);
  909.     end;     #for i := 1 to card action_list
  910.  
  911.     _ReleaseMouse();                    # release possible pressed items
  912.     for each theKey in keysPressed
  913.         _ReleaseKey({theKey});
  914.     
  915. #        _ReleaseKey({shiftKey});        # 07/12/94 SBR commented out (new clean up method)
  916. #        _ReleaseKey({optionKey});
  917. #        _ReleaseKey({commandKey});
  918.     return true;
  919. end;
  920.  
  921.  
  922. #########################################################################
  923. #    task                    select_popup(cntrlDesc, value)
  924. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  925. #    Description:    This task is a general purpose popup menu selector. It
  926. #                    is for popup menus which VU can only see as a control.
  927. #                    To combat the problem of menus which don't fit on the
  928. #                    screen and become scrollable when they are selected,
  929. #                    this task moves up or down the menu one item at a time.
  930. #    Parameters:        cntrlDesc:        A descriptor of the control.
  931. #                    value:            The desired item number where the lowest is 0.
  932. #    Returns:        success: true, failure: false
  933. #    Examples:        select_popup("Geneva", 4);
  934. #    Assumptions:    None
  935. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  936. #    History:
  937. #        2/27/91        EH        Creation as part of SelectLib.vu for 007.
  938. #        3/4/92        Jason Marsh        Incorporated into Clouseau.Lib.
  939. #        09/27/96      BRL/MSO            Added SPEC exception handling
  940. #########################################################################
  941. task    select_popup(cntrlDesc, value)
  942. begin
  943.     # variables for return values
  944.     complete := true;         # result code RETURNED if tool could be completely run
  945.     incomplete := false;     # result code RETURNED if tool could not be completely run
  946.     status := complete;        # result code to be returned by this task
  947.     
  948.     if not (cntrlDesc)
  949.         return RIncomplete("select_popup: Empty descriptor");            # RIncomplete always returns false
  950.     
  951.     if not (await_presence(cntrlDesc))                                    # Make sure popup is visible.
  952.         return RIncomplete("select_popup: Could not find control");                    
  953.         
  954.       
  955.     cntrlDesc := _Match(cntrlDesc);
  956.     cntrlLoc := cntrlDesc.r;                                    # Location of control.
  957.     cntrlSet := cntrlDesc.s;                                    # What the control is set to.
  958.     
  959.     if (cntrlSet[1] = value)                                            # don't do anything if we already have the right value.
  960.          return complete;
  961.          
  962.     if ((value > cntrlSet[2]) or (value < 0))                             # value not in possible range.  0 is assumed to be the
  963.         return incomplete;                                                # lowest value since we have no way of knowing. 
  964.     
  965.     if (cntrlSet[1] > value) 
  966.     begin
  967.           dist := -16;                                                    # move up the popup 'stop' times
  968.         stop := cntrlSet[1] - value;
  969.     end;
  970.     else 
  971.     begin
  972.           dist := 16;                                                        # move down the popup 'stop' times
  973.         stop := value - cntrlSet[1];
  974.     end;
  975.     
  976.     for i := 1 to stop
  977.     begin
  978.         _Move('a',{(cntrlLoc[3] - 10), (cntrlLoc[4] - 10)});            # Move mouse to control.
  979.         _PressMouse();                                                    # press button
  980.         wait(1);                                                        # wait a second for control to select.
  981.         _Move('r',{0, dist});                                        # move up or down to select item in popup
  982.         wait(1);                                                        # wait for control to catch up to mouse.
  983.         _ReleaseMouse();                                                # release button to select.
  984.           wait(1);
  985.     end;
  986.       
  987.     return complete;
  988. end;
  989.  
  990.  
  991. #########################################################################
  992. #    task                    twitch(appName, v_level)
  993. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  994. #    Description:    Click on the twitch icon.  If appName (regular expr)
  995. #                    is supplied, keep twitching until we reach the desired
  996. #                    application, or until we cycle through everything.
  997. #    Parameters:        appName:        name of process to switch to.
  998. #                    v_level:        verbosity level for log output
  999. #    Returns:        false if we are still in the same application after
  1000. #                    attempting to twitch. This will also happen if a
  1001. #                    non-existent appName is passed in.
  1002. #    Examples:        twitch("Scrapbook");
  1003. #    Assumptions:    We assume that the first FOUR items of the application
  1004. #                    are NOT application names, and that the rest are.
  1005. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1006. #    History:
  1007. #        7/25/90        Alan Liu        Creation as part of FinderLib.vu for 007
  1008. #        3/4/92        Jason Marsh        Incorporated into Clouseau.Lib
  1009. #        10/27/93    SBR                Added v_level to twitch failure
  1010. #        09/27/96      BRL/MSO            Added SPEC exception handling
  1011. #########################################################################
  1012. task    twitch(appName := "",v_level := 5)
  1013. begin
  1014.     global g_CurApName;
  1015.     
  1016.     try 
  1017.         match [application t:?g_CurApName]; (*name of the current app*)
  1018.     catch theError
  1019.         ExceptionDispatcher(theError,,{"match 1 in twitch", {appName,v_level}});
  1020.         
  1021.     if g_CurApName = appName
  1022.         return RStatus("twitch: current application is {appName}",v_level);
  1023.     start_app := g_CurApName;
  1024.  
  1025.     try 
  1026.         match [menuItem t:'Hide Others' m:[menu o:?appMenu]]!; (*will return 0 if can't find it*)
  1027.     catch theError
  1028.         ExceptionDispatcher(theError,,{"match 2 in twitch", {appName,v_level}});
  1029.  
  1030.     if appMenu 
  1031.     begin
  1032.         if appName 
  1033.         begin
  1034.             _Select([menuItem t:appName m:appMenu], true);
  1035.         end;
  1036.         else 
  1037.         begin
  1038.             try 
  1039.                 tMatch := match [menuItem m:appMenu c:'' o:?i]!;
  1040.             catch theError
  1041.                 ExceptionDispatcher(theError,,{"match 3 in twitch", {appName,v_level}});
  1042.                 
  1043.             if tMatch 
  1044.             begin
  1045.                 j := i+1;
  1046.                 if not _MatchBoolean([menuItem m:appMenu o:j]) 
  1047.                     j := 5;
  1048.                 if i <> j 
  1049.                     _Select([menuItem m:appMenu o:j], true);
  1050.             end;
  1051.         end;
  1052.     end;
  1053.     
  1054.     wait(1); (*if we don't do this we match the original app again*)
  1055.  
  1056.     try 
  1057.         match [application t:?g_CurApName]!;
  1058.     catch theError
  1059.         ExceptionDispatcher(theError,,{"match 4 in twitch", {appName,v_level}});
  1060.  
  1061.     if g_CurApName = start_app
  1062.     begin
  1063.         if g_CurApName <> "Finder"
  1064.             return RIncomplete ("twitch: {appName} unsuccessful.  Current application is '{g_CurApName}'",v_level);
  1065.         else 
  1066.             return RStatus ("twitch: only Finder currently running",v_level);
  1067.     end;
  1068.     else 
  1069.         return RStatus ("twitch: {appName} successful.  Current application is '{g_CurApName}'",v_level);
  1070. end;
  1071.     
  1072.     
  1073. #########################################################################
  1074. #    task                    close_all_windows(keepWindow, v_level)
  1075. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1076. #    Description:    Close all windows except the named window, in an effort
  1077. #                    to bring it to the front.  Return false if successful
  1078. #                    (the named window is now frontmost), true on failure.
  1079. #                    If keepWindow is empty ("") then all windows will be closed.
  1080. #                    We watch for the System 7.X 'Desktop' window and try
  1081. #                    to send it to the back when we encounter it. If it is
  1082. #                    the only window open, then we return.
  1083. #    Parameters:        keepWindow:        name of window to keep open
  1084. #                    v_level:        verbosity level for log output
  1085. #    Returns:        Nothing
  1086. #    Examples:        close_all_windows();
  1087. #    Assumptions:    None
  1088. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1089. #    History:
  1090. #        7/25/90        Alan Liu        Creation as part of WindowLib.vu for 007
  1091. #        03/04/92    Jason Marsh        Incorporated into Clouseau.Lib
  1092. #        09/04/95    SBR                Radar 1272777: Changed from true to false (below)
  1093. #        09/27/96      BRL/MSO            Added SPEC exception handling
  1094. #########################################################################
  1095. task    close_all_windows(keepWindow := "", v_level:=5)
  1096. begin
  1097.     stop := false;
  1098.     
  1099.     try
  1100.         frontWind := match [window o:1 t:?frontName];
  1101.     catch theError
  1102.         ExceptionDispatcher(theError,,{"match 1 in close_all_windows", {keepWindow, v_level}});
  1103.         
  1104.     while frontWind and (not stop)
  1105.     begin
  1106.         if _MatchBoolean([window o:1 r:{0,0,0,0}])            # Desktop is in front
  1107.         begin
  1108.             if _MatchBoolean([window o:2])
  1109.                 _Select([window o:2], true);
  1110.             else 
  1111.                 stop := true;
  1112.         end;
  1113.         else 
  1114.         begin
  1115.             if (keepWindow and (frontName = keepWindow))
  1116.                 return true;
  1117.             else if dismiss_dialog(,v_level)
  1118.             begin
  1119.                 # Changed from "stop := true" for Radar 1272777
  1120.                 stop := false;
  1121.             end;
  1122.         end;
  1123.         
  1124.         try
  1125.             frontWind := match [window o:1 t:?frontName];
  1126.         catch theError
  1127.             ExceptionDispatcher(theError,,{"match 2 in close_all_windows", {keepWindow, v_level}});
  1128.     end;
  1129.     return not (keepWindow <> "");
  1130. end;
  1131.  
  1132.  
  1133. #########################################################################
  1134. #    task                    relocate_window(newRect, v_level)
  1135. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1136. #    Description:    Set the front window to the given rect.
  1137. #                    Checks to make sure the size box is not moved offscreen
  1138. #                    before it is used. Also handles situations that would
  1139. #                    require more than a two-step drag-size call.
  1140. #    Parameters:        newRect:        new location and size of window
  1141. #                    v_level:        verbosity level for log output
  1142. #    Returns:        true if the move was successful 
  1143. #                    false if the move failed.
  1144. #    Examples:        relocate_window({100,100,230,230});
  1145. #    Assumptions:    Assumes only 1 monitor is connected, or that the window
  1146. #                    is/will be completely on the menu monitor.
  1147. #                    Also re-sizes windows in two steps - horizontally and
  1148. #                    vertically, rather than one smooth diagonal movement.
  1149. #                    Does not account for illegal moves of windows caused by
  1150. #                    dragging them onto the menubar, though this does will
  1151. #                    result in a FAIL result.
  1152. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1153. #    History:
  1154. #        7/25/90     Alan Liu        Creation as part of WindowLib.vu for 007.
  1155. #        8//91        Jonathan Marsh    Robusticised it.
  1156. #        3/23/92        Jason Marsh        Incorporated into Clouseau.lib.
  1157. #        09/27/96      BRL/MSO            Added SPEC exception handling
  1158. #########################################################################
  1159. task    relocate_window(newRect := {2, 22, 202, 222}, v_level := 5)
  1160. begin
  1161.     rStatus("relocate_window:  Attempting to resize window to " + list_to_str(newRect), 4);
  1162.     
  1163.     try 
  1164.         frontWind := match [window o:1 r:?oldRect]!;
  1165.     catch theError
  1166.         ExceptionDispatcher(theError,,{"match in relocate_window()", {newRect, v_level}});
  1167.         
  1168.     if (frontWind) 
  1169.     begin
  1170.             # Note that this is defined only for the startup monitor.
  1171.             #    We check for legal windows against this screen only.
  1172.         screenRect := _Match([screen m:true], true).r;
  1173.         
  1174.             # If dragging before sizing results in the size box being dragged offscreen,
  1175.             #    then size before dragging.  In order to do this we ensure that the window
  1176.             #    is at its farthest left point (of old and new) before sizing it.
  1177.             # We must sometimes break this move into 3 steps (size,drag,size) - i.e. changing
  1178.             #    a short wide window near the bottom of the screen cannot be resized to 
  1179.             #    a tall narrow window near the right of the screen in one drag, one size.
  1180.             # Therefore, break the horizontal and vertical moves down separately.
  1181.         
  1182.         if newRect[1] > oldRect[1] 
  1183.         begin
  1184.             presizedW := TRUE;
  1185.             _Size([window o:1], 'w', {newRect[3]-newRect[1]} );
  1186.         end;
  1187.         if newRect[2] > oldRect[2] 
  1188.         begin
  1189.             presizedH := TRUE;
  1190.             _Size([window o:1], 'h', {newRect[4]-newRect[2]} );
  1191.         end;
  1192.         
  1193.             # Do the drag if needed.
  1194.         if (oldRect[1] <> newRect[1] OR oldRect[2] <> newRect[2])
  1195.             _Drag(frontWind, 'a', {newRect[1], newRect[2]});
  1196.             
  1197.             # Do any sizing we haven't already done.
  1198.         if (oldRect[3] - oldRect[1]) <> (newRect[3] - newRect[1]) AND NOT presizedW
  1199.             _Size(frontWind, 'w', {newRect[3]-newRect[1]} );
  1200.         if (oldRect[4] - oldRect[2]) <> (newRect[4] - newRect[2]) AND NOT presizedH
  1201.             _Size(frontWind, 'h', {newRect[4]-newRect[2]} );
  1202.  
  1203.             # Make sure the window is actually in the right place.
  1204.         if _MatchBoolean([window o:1 r:newRect]) 
  1205.         begin
  1206.             if RXStatus(v_level)
  1207.                 println "relocate_window: sized front window to ", newRect;
  1208.             return true;
  1209.         end;
  1210.         else 
  1211.         begin
  1212.             rDumpState();
  1213.             return RIncomplete("relocate_window: resize window failed");
  1214.         end;
  1215.     end;
  1216.     else
  1217.         return RIncomplete("relocate_window: there is no front window");
  1218. end;
  1219.  
  1220.  
  1221. #########################################################################
  1222. #    task                    dismiss_dialog(preferredButton, v_level)
  1223. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1224. #    Description:    Dismiss a frontmost dialog, if there is one, resorting
  1225. #                    to whatever means are necessary (i.e., files may NOT
  1226. #                    be saved).  Algorithm:
  1227. #                        1. If there is a close box, call close_window().
  1228. #                        2. If there is a preferred button parameter, and
  1229. #                            it is present, use it.
  1230. #                        3. Examine the enabled buttons. If there is exactly
  1231. #                            one, select it, unless it contains the word 'launch'.
  1232. #                        4. If there are no enabled buttons, indicate an error.
  1233. #                        5. If there is more than one, apply our preference
  1234. #                            list -- if none of the preferred buttons is present,
  1235. #                            then do nothing and indicate an error.
  1236. #    Parameters:        preferredButton: Name of most likely button to dismiss dialog
  1237. #                    v_level:        verbosity level for log output
  1238. #    Returns:        true if successful, false if not
  1239. #    Examples:        dismiss_dialog();
  1240. #    Assumptions:    None
  1241. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1242. #    History:
  1243. #        7/25/90     Alan Liu        Creation as part of WindowLib.vu for 007.
  1244. #        3/23/92        Jason Marsh        Incorporated into Clouseau.lib.
  1245. #        09/27/96      BRL/MSO            Added SPEC exception handling
  1246. #########################################################################
  1247. task    dismiss_dialog(preferredButton := "", v_level :=5)
  1248. begin
  1249.     try 
  1250.         frontWind := match [window t:?tw o:1 c:?hasClose k:?kList r:?rw]!;
  1251.     catch theError
  1252.         ExceptionDispatcher(theError,,{"match in dismiss_dialog()", {preferredButton, v_level}});
  1253.  
  1254.     if frontWind
  1255.     begin
  1256.         if (hasClose)
  1257.             return close_window(tw,v_level);
  1258.         else if (preferredButton <> "" and _MatchBoolean([button t:preferredButton w:1 e:true]))
  1259.         begin
  1260.             _Select([button t:preferredButton w:1], true);
  1261.             return RStatus("dismiss_dialog selected preferred button ∂'{preferredButton}∂'",v_level);
  1262.         end;                                #RStatus always returns true
  1263.         else 
  1264.         begin
  1265.             (*Remove everything except enabled buttons*)
  1266.             for i := card kList to 1 step -1
  1267.             begin
  1268.                 if (not kList[i].e) or (descType(kList[i]) <> 'button')
  1269.                     kList := remove(i, kList);
  1270.             end;
  1271.  
  1272.             (*If there is just one enabled button, select it*)
  1273.             if (card kList = 1) 
  1274.             begin
  1275.                 if not (kList[1].t ~= /≈launch≈/) 
  1276.                 begin
  1277.                     _Select(kList[1], false);
  1278.                     if RXStatus(v_level)
  1279.                         println "dismiss_dialog: selected only enabled button ", kList[1];
  1280.                     return true;
  1281.                 end;
  1282.             end;
  1283.             
  1284.             (*If there are no enabled buttons, signal a warning*)
  1285.             else if (card kList < 1)
  1286.                 return RIncomplete("dismiss_dialog: No enabled buttons");    #RIncomplete always returns false
  1287.                 
  1288.             (*Otherwise apply our preference list*)
  1289.             else 
  1290.             begin
  1291.                 buttonPref := {'Cancel', 'Quit', 'OK'};
  1292.  
  1293.                 for i := 1 to card buttonPref 
  1294.                 begin
  1295.                     for j := 1 to card kList 
  1296.                     begin
  1297.                         if kList[j].t = buttonPref[i] 
  1298.                         begin
  1299.                             if select_descriptor(kList[j],v_level)
  1300.                                 return true;
  1301.                         end;
  1302.                     end;
  1303.                 end;
  1304.                 
  1305.                 (*Can't decide*)
  1306.                 n := card kList;
  1307.                 RIncomplete("dismiss_dialog: Multiple enabled buttons ({n})");
  1308.                 return false;
  1309.             end;
  1310.         end;
  1311.     end;
  1312.     else return false;
  1313. end;
  1314.  
  1315.  
  1316. #########################################################################
  1317. #    task                    select_window(specifier, v_level)
  1318. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1319. #    Description:    Select the given window by using the built in VU select
  1320. #                    command.  Returns false if the window could not be
  1321. #                    found or otherwise failed to come to the front. 
  1322. #    Parameters:        specifier:        name or ordinal of window to select
  1323. #                    v_level:        verbosity level for log output
  1324. #    Returns:        success: true, failure: false
  1325. #    Examples:        select_window("Control Panels");
  1326. #    Assumptions:    None
  1327. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1328. #    History:
  1329. #        7/25/90     Alan Liu        Creation as part of WindowLib.vu for 007.
  1330. #        3/23/92        Jason Marsh        Incorporated into Clouseau.lib.
  1331. #        09/27/96      BRL/MSO            Added SPEC exception handling
  1332. #########################################################################
  1333. task    select_window(specifier:="", v_level:= 5)
  1334. begin
  1335.      if(specifier = "")                         #RIncomplete always returns false
  1336.         return RIncomplete("select_window: Null specifier passed as a parameter");
  1337.         
  1338.     if not (TypeOf(specifier) = 'integer') 
  1339.     begin
  1340.         theDesc := _Match([window t:specifier],true);
  1341.         if (not theDesc) 
  1342.             return RIncomplete("select_window: Couldn't match a window of title: {specifier}");
  1343.     end;
  1344.     else if (specifier > 0) 
  1345.     begin
  1346.         theDesc := _Match([window o:specifier],true);
  1347.         if (not theDesc) 
  1348.             return RIncomplete("select_window: Couldn't match a window of ordinality: {specifier}");
  1349.     end;
  1350.     else if (specifier = 0) 
  1351.     begin
  1352.         theDesc := _Match([window c:true g:true],true);
  1353.         if (not theDesc) 
  1354.             return RIncomplete("select_window: No windows open");
  1355.     end;
  1356.     if theDesc.r = {0,0,0,0}                 #coordinates for the Desktop, which shows up as a window
  1357.         return RIncomplete("select_window: no windows are open to select");
  1358.         
  1359.     windOrd := theDesc.o;
  1360.     title := theDesc.t;
  1361.     if windOrd > 1
  1362.         _Select([window o:windOrd t:title], true);
  1363.     if not await_presence([window o:1 t:title])
  1364.         return RIncomplete("select_window: failed to select window");
  1365.     RStatus("select_window: selected window titled: '{title}' o: {windOrd}", v_level);
  1366.     return true;
  1367. end;
  1368.  
  1369.  
  1370. #########################################################################
  1371. #    task                    close_window(windName, v_level)
  1372. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1373. #    Description:    Close the named window, and wait for it to go away.
  1374. #                    This additional handshaking is sometimes helpful if
  1375. #                    scripts are running ahead of themselves. If no windName
  1376. #                    passed in, close the frontmost window.
  1377. #    Parameters:        windName:        name  of window to close
  1378. #                    v_level:        verbosity level for log output
  1379. #    Returns:        success: true, failure: false
  1380. #    Examples:        close_window("Control Panels");
  1381. #    Assumptions:    None
  1382. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1383. #    History:
  1384. #        07/25/90     Alan Liu        Creation as part of WindowLib.vu for 007.
  1385. #        03/23/92    Jason Marsh        Incorporated into Clouseau.lib.
  1386. #        02/22/95    SBR                added v_level to "has no close box" error msg
  1387. #        09/27/96      BRL/MSO            Added SPEC exception handling
  1388. #########################################################################
  1389. task    close_window(windName :="", v_level:= 5)
  1390. begin
  1391.     if windName = ""
  1392.     begin
  1393.         try 
  1394.             match [window t:?windName o:1]!; #If no windName, close the frontmost window
  1395.         catch theError
  1396.             ExceptionDispatcher(theError,,{"match 1 in close_window()", {windName, v_level}});
  1397.             
  1398.         front := true;
  1399.     end;
  1400.         
  1401.     try 
  1402.         windowToClose := match [window t:windName c:?hasClose r:?rw o:?WindOrd]!;
  1403.     catch theError
  1404.         ExceptionDispatcher(theError,,{"match 2 in close_window()", {windName, v_level}});
  1405.     
  1406.     if windowToClose
  1407.     begin
  1408.         if (hasClose) 
  1409.         begin
  1410.             if windName = 'Alarm Clock' 
  1411.             begin
  1412.                 (*There's no real close box; fake it out*)
  1413.                 _Move('a', {rw[1] + 16, rw[2] + 8});
  1414.                 _Click();
  1415.             end;
  1416.             else if (rw = {0,0,0,0}) 
  1417.             begin
  1418.                 if _MatchBoolean([window o:2])
  1419.                     _Select([window o:2], true);
  1420.                 return false;
  1421.             end;
  1422.             else 
  1423.             begin
  1424.                 if windOrd > 1 
  1425.                     if not (select_window(windName,v_level))
  1426.                         return false;
  1427.                 RStatus("close_window: closing window ∂'{windName}∂'", v_level);
  1428.                 
  1429.                 _Close( [window o:1], true);
  1430.             end;
  1431.         end;
  1432.         else 
  1433.             return RIncomplete("close_window: ∂'{windName}∂' has no close box", v_level);
  1434.         
  1435.         noErr := (await_absence( [window t:windName], 15 ));
  1436.         if not (noErr)
  1437.             RDumpState(,v_level);
  1438.         return noErr;
  1439.     end;
  1440.     else 
  1441.         return RIncomplete("close_window: ∂'{windName}∂' not on screen");
  1442. end;
  1443.  
  1444.  
  1445. #########################################################################
  1446. #    task                    key_eq(key, modifier, v_level)
  1447. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1448. #    Description:    Type the key specified with the modifiers given.
  1449. #                    usage:  key_eq("o"); 
  1450. #    Parameters:        key:            Key to type
  1451. #                    modifier:        Modifier keys to hold down while pressing the key
  1452. #                        Command             = 1 (default)
  1453. #                        Option                 = 2 
  1454. #                        Shift                = 3
  1455. #                        Control             = 4
  1456. #                        Command and Option    = 5
  1457. #                        Command and Shift    = 6    
  1458. #                    v_level:        verbosity level for log output
  1459. #    Returns:        success: true, failure: false
  1460. #    Examples:        key_eq("o");      Use non-shifted characters for normal menu key commands
  1461. #                                    even though the menu manager displays them as shifted.
  1462. #                    key_eq("#");     Use shifted characters for FKEYs, e.g. cmd-shift-3,
  1463. #                                    or when a menu key command requires the shift key.
  1464. #    Assumptions:    None
  1465. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1466. #    History:
  1467. #        07/25/90    Alan Liu        Creation as part of WindowLib.vu for 007.
  1468. #        03/23/92    Jason Marsh        Incorporated into Clouseau.lib.
  1469. #        07/07/94    SBR                Added comments for shift key usage.
  1470. #        06/01/96    MSO                Added command and shift modifier
  1471. #        09/27/96      BRL/MSO            Added SPEC exception handling
  1472. #########################################################################
  1473. task    key_eq(key,modifier := 1, v_level:=5)
  1474. begin
  1475.     modifierList := { {commandKey},{optionKey},{shiftKey},{controlKey},{commandKey,optionKey},{commandKey,shiftKey} };
  1476.     RStatus("key_eq: typed the ∂'{key}∂' key with modifier {modifier}",v_level); 
  1477.     _PressKey(modifierList[modifier]) ;
  1478.     wait(0,0,0,250);        # extra 1/4 second for the modifiers to register
  1479.     _Type({ key });
  1480.     _ReleaseKey(modifierList[modifier]);
  1481.     return true;
  1482. end;
  1483.  
  1484.  
  1485. #########################################################################
  1486. #    task    FindFile(pSearchArgument, pSearchBy, pSearchConstraint, 
  1487. #                     pSearchLocation, pActionWhenFound, v_level)
  1488. #    Version 1.0d1
  1489. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1490. #    Description:    Find a file in the System 7 Finder using the Find File DA.
  1491. #                    This version allows simple search criteria only. It is structured for 
  1492. #                   time efficiency.
  1493. #    Parameters:        pSsearchArgument:    Value of the argument to search on.  This value
  1494. #                                        changes depending on the searchBy parameter as follows.
  1495. #                    pSearchBy:            What attribute of the file to search by.  
  1496. #                    pSearchConstraint:    Searching constraints.  This value changes depending on the
  1497. #                                        pSearchBy parameter for the different searchBy values.
  1498. #
  1499. #                        pSearchBy        |    pSearchConstraint        |    pSsearchArgument (mandatory)
  1500. #                    --------------------+---------------------------+---------------------------------
  1501. #                        name (default)    | {contains (default),        |    <string>
  1502. #                                        |  starts with, ends with,    |
  1503. #                                        |  is, is not, doesn't         |
  1504. #                                        |  contain}                    |
  1505. #                        size            | †                            |    †
  1506. #                        kind            | {is, is not}                |    {alias, application, clipping
  1507. #                                        |                            |     file, ctrl panel, document,
  1508. #                                        |                            |     extension, folder, font,
  1509. #                                        |                            |     letter, sound, stationery}
  1510. #                        label            | †                            |    †
  1511. #                        date created    | †                            |    †
  1512. #                        date modified    | †                            |    †
  1513. #                        version            | {is, is not}                |    <string>
  1514. #                        comments        | †                            |    †
  1515. #                        lock attribute    | †                            |    †
  1516. #                        folder attribute| †                            |    †
  1517. #                        file type        | †                            |    †
  1518. #                        version            | †                            |    †
  1519. #                            †: not on this version
  1520. #                    pSearchLocation:    Where to perform search. Possible values are:
  1521. #                                        0         on all disks     (default)
  1522. #                                        1         on local disks
  1523. #                                        2        on mounted servers
  1524. #                                        3         on the desktop
  1525. #                                        4        in the finder selection
  1526. #                                        <str>    pSearchLocation 
  1527. #                    pActionWhenFound:    Indicate the task what to do once the item has been found.
  1528. #                                        Possible values are:     
  1529. #                                        launch:         quit Find File and open item (default).
  1530. #                                        open :         open item.
  1531. #                                        open folder: open the item's enclosing folder.
  1532. #                    v_level:    verbosity level for log output.
  1533. #                                v_level = 5    (default)
  1534. #    Returns:        true:    file found..
  1535. #                    false:    file not found
  1536. #    Examples:        findFile("QuickMail","name","contains",1,6);    # Search file 'QuickMail' on local disks.
  1537. #                    findFile("doom");                                # Search file 'Doom; on all disks.
  1538. #                    findFile('folder','kind','is not','backUp');    # Search all non-folders on 'backUp'.
  1539. #                    findFile('2.1',"version",'is',,open);            # Search files with V 2.1 on all disks
  1540. #                                                                        and open file w/o quiting Find File.
  1541. #    Assumptions:    VU 2.1.1.
  1542. #                    requires: Clouseau.lib, ExceptionHandling.lib, Report.lib, VUAid.tool.
  1543. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1544. #    History:
  1545. #        09/09/96    Masa    Created.
  1546. #        09/16/96    Masa    included exception handling.
  1547. #        10/29/96    Masa    debugged version.
  1548. #        11/08/96    Masa    modified await_absence for 'Find File≈'
  1549. #        12/05/96    Masa    Changed logic: gItemNotFound to gItemFound
  1550. #        12/10/96    SBR/Masa    Added 50ms delay to [option] double-click for launch.
  1551. #                                modified await_absence for 'Find File≈' from window to application
  1552. #        01/31/97    SBR        Removed global gItemFound; return true/false, not badLaunch.
  1553. #########################################################################
  1554. task    FindFile(    pSearchArgument := '', pSearchBy := 'name', pSearchConstraint := 'is', 
  1555.                     pSearchLocation := 0, pActionWhenFound := 'launch', v_level:= 3 )
  1556. begin
  1557.     # INITIALIZATION
  1558.  
  1559.     kSearchVolXCoord := 150;
  1560.     kSearchVolYCoord := 35;
  1561.     kSearchByXCoord := 80;
  1562.     kSearchByYCoord := 75;
  1563.     kPopUpDisplacement := 15;
  1564.     kConstraintRegionOffset := 3;
  1565.     kArgumentRegionOffset := 4;
  1566.     kMaxArgumentLength := 15;
  1567.     kXYOffset := 20;
  1568.     kAwaitTime := 60;
  1569.     
  1570.     found := false;
  1571.     
  1572.     
  1573.     # DISPLAY HEADER FOR FindFile() ON NOTEBOOK
  1574.     
  1575.     switch pSearchLocation
  1576.     begin
  1577.         case 0:        RStatus("   ∂'on all disks∂'",v_level);
  1578.         case 1:        RStatus("   ∂'on local disks∂'",v_level);
  1579.         case 2:        RStatus("   ∂'on mounted servers∂'",v_level);
  1580.         case 3:        RStatus("   ∂'on the desktop∂'",v_level);
  1581.         case 4:        RStatus("   ∂'in the finder selection∂'",v_level);
  1582.         default:    RStatus("   ∂'on {pSearchLocation}∂'",v_level);
  1583.     end;
  1584.     RStatus("initiating Find File for: ∂'{pSearchArgument} by {pSearchBy} {pSearchConstraint} on {pSearchLocation}∂'",v_level);
  1585.     
  1586.     
  1587.     
  1588.     # VALIDATE SEARCH ARGUMENT FIRST FOR EFFICIENCY. 
  1589.     # If this parameter has no value then there is nothing we can do thus complain and quit!
  1590.     
  1591.     if (pSearchArgument = '')
  1592.     begin
  1593.         RError('FindFile: Search argument missing (i.e., 1st parameter)',v_level);
  1594.         return false;
  1595.     end;
  1596.     
  1597.     
  1598.     
  1599.     # GENERATE INTERNAL ORDINALITY FOR THE FIND FILE DIALOG BOX
  1600.     # This does not include all pSearchBy options yet.
  1601.     
  1602.     searchByOffset := assoc(pSearchBy, {{'name',0},{'kind',2},{'version',6}});
  1603.     switch pSearchBy
  1604.     begin
  1605.         case 'name':
  1606.             searchConstraintOffset := assoc(pSearchConstraint, 
  1607.                                             {{'contains',0},{'starts with',1},{'ends with',2},{'is',3}});
  1608.         case 'kind':
  1609.         begin
  1610.             searchConstraintOffset := assoc(pSearchConstraint, {{'is',0},{'is not',1}});
  1611.             searchArgumentOffset := assoc(pSearchArgument, {{'alias',0},{'application',1},
  1612.                                          {'control panel',3},{'document',4},{'extension',5},{'folder',6}});
  1613.         end;
  1614.         case 'version':
  1615.             searchConstraintOffset := assoc(pSearchConstraint, 
  1616.                                             {{'is',0},{'is not',1},{'ends with',2},{'is',3}});
  1617.         default:
  1618.         begin
  1619.             RError("FindFile: 'pSearchBy' parameter is invalid.",v_level);
  1620.             return false;
  1621.         end;
  1622.     end;
  1623.     
  1624.     
  1625.     
  1626.     # OPEN FIND FILE DA, MAKE THE FIND FILE WINDOW FRONTMOST, AND RELOCATE IT ON SCREEN IF NEEDED
  1627.     
  1628.     if not _MatchBoolean([application t:'Find File'])
  1629.     begin
  1630.         useAppleMenu := true;
  1631.         if _MatchBoolean([application t:'Finder'])
  1632.         begin
  1633.             key_eq('f');
  1634.             if await_presence([application t:'Find File'], kAwaitTime)    
  1635.                 useAppleMenu := false;
  1636.         end;
  1637.         
  1638.         if useAppleMenu
  1639.         begin
  1640.             if not select_menuItem('Find File', 1)
  1641.             begin
  1642.                 RError('FindFile: Target has no Find File DA installed...',v_level);
  1643.                 return false;
  1644.             end;
  1645.  
  1646.             if not await_presence([application t:'Find File'], kAwaitTime)
  1647.             begin
  1648.                 RError('FindFile: Find File menu item selected, DA did not come to the front...',v_level);
  1649.                 return false;
  1650.             end;
  1651.         end;
  1652.     end;
  1653.  
  1654.  
  1655.     # MAKE SURE FIND FILE WINDOW IS IN FRONT WITH ONLY ONE LINE OF CHOICES
  1656.  
  1657.     key_eq('f');    # Activates Find File window if Items Found window was in front.
  1658.     await_presence([window t:/Find File≈/ o:1], kAwaitTime);
  1659.  
  1660.     while _MatchBoolean([button t:'Fewer Choices' w:1])
  1661.     begin
  1662.         saveSpeed := typeSpeed(10);
  1663.         key_eq('rrrrrrrrrrr'); 
  1664.         typeSpeed(saveSpeed);
  1665.     end;
  1666.     
  1667.  
  1668.     # SET ALL NECESSARY PARAMETERS IN FIND FILE DIALOG BOX
  1669.     
  1670.     currentWindow := _Match([window o:1]);
  1671.     windRect := currentWindow.r;
  1672.     volValue := currentWindow.k[3].s[1];
  1673.     if volValue  <> 1
  1674.     begin
  1675.         maxVolValue := currentWindow.k[3].s[2];
  1676.         shiftFindFileWindowY := maxVolValue * kPopUpDisplacement + kXYOffset;
  1677.         if windRect[2] < shiftFindFileWindowY                        # if needed, relocate Find File window
  1678.         begin
  1679.             move_mouse({'absolute',{windRect[1],windRect[2]},'down',{windRect[1],shiftFindFileWindowY},
  1680.                         'wait1','up'});
  1681.             currentWindow := _Match([window o:1]);
  1682.             windRect := currentWindow.r;
  1683.         end;
  1684.         initXCoord := windRect[1] + kSearchVolXCoord;
  1685.         initYCoord := windRect[2] + kSearchVolYCoord;
  1686.         finalYCoord := windRect[2] + (kSearchVolYCoord - (kPopUpDisplacement * (volValue - 1)));
  1687.         move_mouse({'absolute',{initXCoord,initYCoord},'down',{initXCoord,finalYCoord},'wait1','up'});
  1688.     end;    
  1689.     if pSearchBy  <> 'name'
  1690.     begin
  1691.         initXCoord := windRect[1] + kSearchByXCoord;
  1692.         initYCoord := windRect[2] + kSearchByYCoord;
  1693.         finalYCoord := windRect[2] + kSearchByYCoord + kPopUpDisplacement * searchByOffset;
  1694.         move_mouse({'absolute',{initXCoord,initYCoord},'down',{initXCoord,finalYCoord},'wait1','up'});
  1695.     end;
  1696.     if pSearchConstraint  <> 'contains'
  1697.     begin
  1698.         initXCoord := windRect[1] + kSearchByXCoord * kConstraintRegionOffset;
  1699.         initYCoord := windRect[2] + kSearchByYCoord;
  1700.         finalYCoord := windRect[2] + kSearchByYCoord + kPopUpDisplacement * searchConstraintOffset;
  1701.         move_mouse({'absolute',{initXCoord,initYCoord},'down',{initXCoord,finalYCoord},'wait1','up'});
  1702.     end;
  1703.     
  1704.     initXCoord := windRect[1] + kSearchByXCoord * kArgumentRegionOffset;
  1705.     initYCoord := windRect[2] + kSearchByYCoord;
  1706.     if pSearchBy = 'kind'                                        # if pSearchBy 'kind'
  1707.     begin
  1708.         _PressMouse();
  1709.         finalYCoord := windRect[2] + kSearchByYCoord + kPopUpDisplacement * searchArgumentOffset;
  1710.         move_mouse({'absolute',{initXCoord,initYCoord},'down',{initXCoord,finalYCoord},'wait1','up'});
  1711.     end;
  1712.     else                                                        # i.e., if pSearchBy 'name' or 'version'
  1713.     begin
  1714.         move_mouse({'absolute',{initXCoord,initYCoord},'click'});
  1715.         type_keys({'latch',commandKey,'a',pSearchArgument});
  1716.     end;
  1717.         
  1718.     # EXECUTE SEARCH
  1719.     
  1720.     type_keys({returnKey});
  1721.     if  (await_absence([window t:/Find File≈/ o:1], kAwaitTime))
  1722.     begin
  1723.         if _MatchBoolean([staticText t:'No items were found.' w:[window t:'' o:1 s:dialog]])
  1724.         begin
  1725.             select_descriptor([button t:'OK']);
  1726.             key_eq('q');
  1727.             RError("FindFile: {pSearchArgument} not found on the selected volume(s).",v_level);
  1728.             return false;
  1729.         end;
  1730.     end;
  1731.     
  1732.     
  1733.     # LOCATE THE ITEM FOUND
  1734.  
  1735.     currentWindow := _Match([window o:1]);
  1736.     if not (currentWindow.t = 'Items Found')
  1737.     begin
  1738.         RError("FindFile: 'Items Found' window not active...",v_level);
  1739.         return false;
  1740.     end;
  1741.     itemsFoundWindowRect := currentWindow.r;
  1742.     if (card pSearchArgument) > kMaxArgumentLength
  1743.     begin
  1744.         searchArgumentLength := (card pSearchArgument);
  1745.         subArgumentBaseIndex := searchArgumentLength - kMaxArgumentLength +1;
  1746.         searchSubArgument := pSearchArgument[subArgumentBaseIndex];
  1747.         for i := (subArgumentBaseIndex + 1) to searchArgumentLength
  1748.         begin
  1749.             searchSubArgument := searchSubArgument + pSearchArgument[i];
  1750.         end;
  1751.         _Match([screen]);
  1752.         positionFound := LocateString(searchSubArgument,locateStringWindowRect,'Geneva',9);
  1753.     end;
  1754.     else
  1755.     begin
  1756.         _Match([screen]);
  1757.         positionFound := LocateString(pSearchArgument,locateStringWindowRect,'Geneva',9);
  1758.     end;
  1759.     if  not positionFound
  1760.     begin
  1761.         RError("FindFile: Could not locate {pSearchArgument} in ∂'Items Found∂' window...",v_level);
  1762.         return false;
  1763.     end;
  1764.     
  1765.     
  1766.     # PERFORM THE ACTION REQUESTED
  1767.     
  1768.     switch pActionWhenFound
  1769.     begin
  1770.         case 'launch':
  1771.         begin
  1772.             move_mouse({'absolute',{positionFound[1], positionFound[2]}});
  1773.             _PressKey({optionKey});
  1774.             _DoubleClick();
  1775.  
  1776.             ### Must wait a short time with option key down, but too long will 
  1777.             ### carry into the app launch - many apps will act differently and fail.
  1778.             ### Wait(1) fails with one target (too long).
  1779.             wait(0,0,0,60);
  1780.             _ReleaseKey({optionKey});
  1781.  
  1782.             if  (await_absence([application t:/Find File≈/ ], kAwaitTime))
  1783.             begin
  1784.                 RStatus("{pSearchArgument} found and launched >>>",v_level);
  1785.                 return true;
  1786.             end;
  1787.             else
  1788.             begin
  1789.                 select_descriptor([button t:'OK']);
  1790.                 key_eq('q');
  1791.                 RError("FindFile: Could not launch {pSearchArgument}...",v_level);
  1792.                 return false;
  1793.             end;
  1794.         end;
  1795.         case 'open':
  1796.         begin
  1797.             move_mouse({'absolute',{positionFound[1],positionFound[2]}});
  1798.             _Click();
  1799.             key_eq('o');
  1800.             if (await_absence([window t:/Find File≈/ o:1], kAwaitTime))
  1801.             begin
  1802.                 RStatus("{pSearchArgument} found and opened >>>",v_level);
  1803.                 return true;
  1804.             end;
  1805.             else
  1806.             begin
  1807.                 RError("FindFile: Could not open {pSearchArgument}...",v_level);
  1808.                 return false;
  1809.             end;
  1810.         end;
  1811.         case 'open folder':
  1812.         begin
  1813.             move_mouse({'absolute',{positionFound[1],positionFound[2]}});
  1814.             _Click();
  1815.             key_eq('e');
  1816.             if (await_absence([window t:/Find File≈/ o:1], kAwaitTime))
  1817.             begin
  1818.                 RStatus("Enclosing folder for {pSearchArgument} has been opened >>>",v_level);
  1819.                 return true;
  1820.             end;
  1821.             else
  1822.             begin
  1823.                 RError("FindFile: Could not open {pSearchArgument}∂'s enclosing folder...",v_level);
  1824.                 return false;
  1825.             end;
  1826.         end;
  1827.         default:
  1828.         begin
  1829.             RError("FindFile: Action to perform after finding {pSearchArgument} is invalid...",v_level);
  1830.             return false;
  1831.         end;
  1832.     end;
  1833.  
  1834. end; 
  1835.     
  1836.  
  1837. #########################################################################
  1838. #    task    find(searchText, expectedKind, constraint, searchBy, searchLocation, allAtOnce, v_level)
  1839. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1840. #    Description:    Find a file in the System 7 Finder using the find command.
  1841. #                    The file type is needed to ensure the right type of file 
  1842. #                    is found.  For example, if an application is desired, it
  1843. #                    shouldn't select a document which happens to have the same
  1844. #                    name.  If a find is successful, the file will be selected
  1845. #                    upon return of this task.
  1846. #    Parameters:        searchText:        Text to search on.  This value changes
  1847. #                                    depending on the searchBy parameter.  For
  1848. #                                    example, when searching by size, searchText
  1849. #                                    will be a number in Kbytes.
  1850. #                    expectedKind:    What type of file is expected to be found.
  1851. #                                    A value of "" means no kind matching is desired.
  1852. #                                    Possible types are:
  1853. #                                        appsysfile (includes DAs, control panels,
  1854. #                                            extensions of all kind, suitcases, files,
  1855. #                                            fonts, sounds, keyboard layouts, & scripts), 
  1856. #                                        folder (includes disks), 
  1857. #                                        document (includes stationery),
  1858. #                                        alias
  1859. #                    constraint:        Searching constraints.  This value changes depending
  1860. #                                    on the searchBy parameter.  For the different searchBy
  1861. #                                    values, possible values are:
  1862. #                                        name:    contains, doesn't contain, starts with,
  1863. #                                                ends with, is, is not
  1864. #                                        size:    is less than, is greater than
  1865. #                                        kind:    contains, doesn't contain
  1866. #                                        version:is, is before, is after, is not
  1867. #                                        comments:contain, do not contain
  1868. #                    searchBy:        What attribute of the file to search by.  Possible values are:
  1869. #                                        name (default)
  1870. #                                        size
  1871. #                                        kind
  1872. #                                        version
  1873. #                                        comments
  1874. #                    searchLocation:    Where to perform search. Possible values are:
  1875. #                                        0 - On all disks (default)
  1876. #                                        1 - On the boot drive
  1877. #                                        8 - Inside the current window
  1878. #                                        9 - The selected items
  1879. #                                            - or -
  1880. #                                        string - volume name to search a particular volume 
  1881. #                                            - or -
  1882. #                                        list - possible enclosing window names (check AFTER the find)
  1883. #                    allAtOnce:        Will find everything at once if true.  Default is false.
  1884. #                                    If this option is selected, then expected kind matching
  1885. #                                    is turned off.
  1886. #                    v_level:        verbosity level for log output
  1887. #    Returns:        true -     an error occured
  1888. #                    false - found file
  1889. #    Examples:        Find("MPW Shell","appsysfile","is","name",1);   # Search for the application 'MPW Shell' on the boot disk
  1890. #                    Find("RoboSport","folder","is",,0);                # Search for folder 'RoboSport' on all disks
  1891. #                    Find("folder","",'contains','kind');            # Search for a folder
  1892. #                    Find("5","",'is less than','size');                # Search for any type of file less than 5k
  1893. #                    Find("Monitors","appsysfile",'is','name',8);    # Search for Monitors CDEV inside the current window
  1894. #    Assumptions:    VU 2.0.1
  1895. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  1896. #    History:
  1897. #        7/26/91 EH        Creation as part of FinderLib.vu for 007.
  1898. #        3/23/92    Jason Marsh        Incorporated into Clouseau.lib.
  1899. #        06/02/93    SBR        Changed default parameters to use quick Find (Fewer Choices)
  1900. #        06/02/93    SBR        Search for bogus item only if needed to save time
  1901. #        06/02/93    SBR        Added ordinals for popups, increased typeSpeed
  1902. #        06/17/93    SBR        Removed unnecessary matches for expectedKind check
  1903. #        06/17/93    SBR        Can pass list of possible enclosing windows in searchLocation
  1904. #        11/29/93    SBR        Added await_presence for Get Info Window
  1905. #        11/29/93    SBR        Increased await_ timeout values in most places for VM stress
  1906. #        01/29/94    SBR        Added multiple item wait loop for candy stripe dialog
  1907. #        03/07/94    GTK        Changed popup ordinals. NOTE: This change is a hack which will
  1908. #                            work only if the search is reset. (i.e. When the bogus item is
  1909. #                            found.) Before this change ordinals weren't working at all anyway.
  1910. #                            This task needs a major rework, so use with caution until then.
  1911. #        05/25/94    SBR        Modified to use _matchBoolean where appropriate
  1912. #        07/06/94    SBR        Reduced await_absence time for 'Stop' button from 32767 to 32706
  1913. #                            to avoid VU 2.0.1 overflow error (32767 max integer value).
  1914. #        07/07/94    SBR        Use cmd-shift-f (or g) to use (or reuse) System 7.0 Find and avoid 
  1915. #                            System 7.5 Find File DA, which is different and not scripted yet. 
  1916. #                            The shift key should be ignored in stock pre-7.5 systems.
  1917. #        09/27/94    SBR        Await_absence [staticText] after the bogus find to avoid skipping 
  1918. #                            the shift key on slow Macs.
  1919. #        08/08/95    SBR        Added pathName comparison for Radar 1275447 
  1920. #        09/27/96      BRL/MSO    Added SPEC exception handling
  1921. #########################################################################
  1922. task    find(searchText, expectedKind := "", constraint := "", searchBy := "",
  1923.                         searchLocation := false,allAtOnce := false, v_level:= 5)
  1924. begin
  1925.     global gPreviousFinderFindString;
  1926.     
  1927.     RStatus("begining Find routine for {searchText}",v_level);
  1928.     # variables for return values
  1929.     complete := true;         # result code RETURNED if tool could be completely run
  1930.     incomplete := false;     # result code RETURNED if tool could not be completely run
  1931.     status := complete;        # result code to be returned by this task
  1932.     found := true;
  1933.     couldntFind := false;
  1934.     prevInfoWindow := [];
  1935.     prevWindowPath := '';
  1936.  
  1937.     if (searchText = "")
  1938.         return incomplete;
  1939.         
  1940.     searchLocationType := typeOf(searchLocation);
  1941.     
  1942.     #### Turn expected kind matching off if allAtOnce is true because there may be more than one
  1943.     if (allAtOnce)
  1944.         expectedKind := "";
  1945.     
  1946.     #### Go to Finder
  1947.     if not _MatchBoolean([application t:"Finder"])            #RIncomplete always returns false
  1948.         if not twitch("Finder") 
  1949.             return RIncomplete("find: Could not make Finder active.");
  1950.     
  1951.     #### Store the existing windows for later (see Radar 1275447)
  1952.     try 
  1953.         match [window t:$oldWindowNames r:$oldWindowRects];
  1954.     catch theError
  1955.         ExceptionDispatcher(theError,,{"match 1 in find", {searchText, expectedKind, constraint, searchBy,
  1956.                         searchLocation, allAtOnce, v_level}});
  1957.  
  1958.     #### Get 7.0 Find window to front
  1959. #    key_eq('F',,6);                    # use cmd-shift-f to use 7.0 Find, not 7.5 Find File DA
  1960. #    if (await_presence([window t:"Find" o:1 g:false z:false c:false],60,,true,6) = error)
  1961.     if not use_7_0_find( false )
  1962.         return RIncomplete("find: Find window did not come to front");
  1963.         
  1964.     ## Select Fewer Choices so that the search parameters are reset
  1965.     
  1966.     if _Match([window o:1]).k[3].t <> 'More Choices' 
  1967.     begin
  1968.         select_descriptor([button t:'Fewer Choices'], v_level);
  1969.         if (await_presence([button t:'More Choices'],60) = error) 
  1970.         begin
  1971.             _Type({ escapekey });
  1972.             return incomplete;
  1973.         end;
  1974.     end;
  1975.  
  1976.     #### Find a bogus item - This is to compensate for a 7.0-7.1 Find bug
  1977.     #### SBR:     Do this only if the current Find item is the same as the
  1978.     ####         previous item, or if the previous item is unknown.
  1979.     if searchText = gPreviousFinderFindString or isUndefined(gPreviousFinderFindString) 
  1980.     begin
  1981.         saveSpeed := typeSpeed(50);
  1982.         
  1983.         _Type({ "Gobblygook! - sdjhfsd", returnKey });
  1984.         typeSpeed(saveSpeed);
  1985.         if (await_presence([staticText t:'No matching items were found.'],300) = error)
  1986.         begin
  1987.             _Type({ escapekey });
  1988.             return incomplete;
  1989.         end;
  1990.         else 
  1991.         begin
  1992.             # 09/27/94 SBR: await_absence to avoid skipping the next shift key on slow Macs
  1993.             
  1994.             _Type({ returnKey });
  1995.             await_absence([staticText t:'No matching items were found.'],300);
  1996.         end;
  1997.     
  1998.         #### Get 7.0 Find window to front again
  1999. #        key_eq('F',,5);                    # use cmd-shift-f to use 7.0 Find, not 7.5 Find File DA
  2000. #        if (await_presence([window t:"Find" o:1 g:false z:false c:false],60,,true,6) = error )
  2001.         if not use_7_0_find( false )
  2002.             return RIncomplete("find: Find window did not come to front the second time");
  2003.     end;
  2004.  
  2005.     #### Open More choices window if not a generic search
  2006.     if (constraint or searchBy or (searchLocation <> false) or allAtOnce) and 
  2007.             searchLocationType <> 'list'
  2008.         if _MatchBoolean([button t:"More Choices"])
  2009.             select_descriptor([button t:"More Choices"], v_level);
  2010.     
  2011.     #### Set parameters
  2012.     if _MatchBoolean([button t:"Fewer Choices"]) 
  2013.     begin
  2014.         ## search by
  2015.         if (select_descriptor([menuItem t:searchBy m:[popup e:true o:7 w:1]], v_level) = error) 
  2016.         begin
  2017.             _Type({ escapeKey });
  2018.             return incomplete;
  2019.         end;
  2020.         
  2021.         ## constraints
  2022.         #### GTK: Changed popup ordinal
  2023.         #if (select_descriptor([menuItem t:constraint m:[popup e:true o:1 w:1]]) = error) 
  2024.         if (select_descriptor([menuItem t:constraint m:[popup e:true o:6 w:1]]) = error) 
  2025.         begin
  2026.             _Type({ escapeKey });
  2027.             return incomplete;
  2028.         end;
  2029.         
  2030.         ## search location (integer)
  2031.         #### GTK: Changed popup ordinal
  2032.         #searchLocMenu := [popup o:6 w:1]!;
  2033.         searchLocMenu := [popup o:5 w:1]!;
  2034.         if searchLocationType = 'integer' 
  2035.         begin
  2036.             if (searchLocation = 0)
  2037.                 select_descriptor([menuitem o:1 m:searchLocMenu]);
  2038.             else if (searchLocation = 1) 
  2039.             begin
  2040.                 if _MatchBoolean([menuitem t:'on all disks' m:searchLocMenu])
  2041.                     select_descriptor([menuitem o:3 m:searchLocMenu]);
  2042.                 else 
  2043.                     select_descriptor([menuitem o:1 m:searchLocMenu]);
  2044.             end;
  2045.             else if (searchLocation = 8)
  2046.                 select_descriptor([menuitem t:/inside≈/ m:searchLocMenu]);
  2047.             else if (searchLocation = 9)
  2048.                 select_descriptor([menuitem t:/≈selected≈/ m:searchLocMenu]);
  2049.         end;
  2050.         else if searchLocationType = 'string' 
  2051.             select_descriptor([menuitem t:"on “{searchLocation}”" m:searchLocMenu]);
  2052.             
  2053.         ## all at once
  2054.         try 
  2055.             match [checkbox t:"all at once" s:?set];
  2056.         catch theError
  2057.             ExceptionDispatcher(theError,,{"match 2 in find", {searchText, expectedKind, constraint, searchBy,
  2058.                         searchLocation, allAtOnce, v_level}});
  2059.             
  2060.         if ((set[1] = 0 and allAtOnce) or (set[1] = 1 and not allAtOnce))
  2061.             select_descriptor([checkbox t:'all at once']);
  2062.     end;
  2063.  
  2064.     #### Type in name and go
  2065.     saveSpeed := typeSpeed(50);
  2066.     
  2067.     _Type({ searchText, returnKey });
  2068.     typeSpeed(saveSpeed);
  2069.  
  2070.     gPreviousFinderFindString := searchText;        # save for next find
  2071.     
  2072.     #### 
  2073.     done := false;
  2074.     while not (done)
  2075.     begin
  2076.         #### Wait 30 seconds until the candy stripe dialog OR one of the possible 
  2077.         #### enclosing windows is in the front. If the candy stripe appears, wait 
  2078.         #### "forever" for it to go away. Added 01/29/94 SBR.
  2079.         
  2080.         previousTime := _Match ([time]);
  2081.             
  2082.         secondsLeft := 30;
  2083.         lookForEnclosingWindow := typeOf(searchLocation) = 'list';
  2084.         
  2085.         while secondsLeft > 0
  2086.         begin
  2087.             if _MatchBoolean([button t:'Stop' o:1 w:'Find' o:1])
  2088.             begin
  2089.                 await_absence([button t:'Stop' w:[window t:'Find' o:1]],32706,,true,6);
  2090.                 secondsLeft := 0;
  2091.             end;
  2092.             
  2093.             else if lookForEnclosingWindow
  2094.             begin
  2095.                 if isMember(_Match([window o:1], true).t, searchLocation)
  2096.                 begin
  2097.                     secondsLeft := 0;
  2098.                 end;
  2099.             end;
  2100.             
  2101.             if secondsLeft
  2102.             begin
  2103.                 secondsLeft := secondsLeft - time_sub(previousTime, _Match ([time]))[1];
  2104.             end;
  2105.         end;
  2106.         
  2107.         #### Wait for dialogs
  2108.         
  2109.         if _MatchBoolean([staticText t:'No matching items were found.' w:[window s:dialog o:1]])
  2110.         begin
  2111.             select_descriptor([button t:'OK']);
  2112.             return couldntFind;
  2113.         end;
  2114.         
  2115.         else if _MatchBoolean([staticText t:/≈was found on the desktop./ w:[window s:dialog o:1]])
  2116.             select_descriptor([button t:'OK']);
  2117.  
  2118.         key_eq('i',, v_level);                                    # Look at the Get Info window
  2119.         await_presence([window t:/≈ Info≈/ o:1],60,,true,6);    # wait before matching
  2120.         
  2121.         infoWindow := _Match([window o:1], true);
  2122.         key_eq('w',, v_level);
  2123.         
  2124.         #### Have we found the same file, if so check the path, we may be done.
  2125.         #### Added pathName comparison for Radar 1275447.
  2126.         if ((prevInfoWindow.r = infoWindow.r) and            # NOTE: Here we cannot use
  2127.                 (prevInfoWindow.t = infoWindow.t) and        # "prevInfoWindow = infoWindow"
  2128.                 (prevInfoWindow.k = infoWindow.k))            # because of a bug in VU equality
  2129.         begin
  2130.             try 
  2131.                 match [window t:?windowName r:?windowRect o:1]!;
  2132.             catch theError
  2133.                 ExceptionDispatcher(theError,,{"match 3 in Find", {searchText, expectedKind, constraint, searchBy,
  2134.                         searchLocation, allAtOnce, v_level}});
  2135.  
  2136.             curWindowPath := '';
  2137.                 
  2138.             while (windowName <> 'Desktop')
  2139.             begin
  2140.                 curWindowPath := windowName + ':' + curWindowPath;
  2141.                 tNameIndex := isMember(windowName, oldWindowNames);
  2142.                 tRectIndex := isMember(windowRect, oldWindowRects);
  2143.                 
  2144.                 if (not tNameIndex) OR (not tRectIndex) OR (tNameIndex <> tRectIndex)
  2145.                     _PressKey({optionKey});
  2146.                 type_keys({'latch', commandKey, upArrowKey});
  2147.                 _ReleaseKey({optionKey});
  2148.                 await_absence([window t:windowName o:1]);
  2149.  
  2150.                 try 
  2151.                     match [window t:?windowName r:?windowRect o:1]!;
  2152.                 catch theError
  2153.                     ExceptionDispatcher(theError,,{"match in Find loop", {searchText, expectedKind, constraint, searchBy,
  2154.                         searchLocation, allAtOnce, v_level}});
  2155.             end;
  2156.             if prevWindowPath = curWindowPath
  2157.                 return couldntFind;
  2158.         end;
  2159.  
  2160.         if (infoWindow.t = 'Find')        # This is for a special case when trying to find the trash.
  2161.         begin                            # The 'couldn't find…' dialog doesn't come up.
  2162.             _Type({ escapeKey });
  2163.             return couldntFind;
  2164.         end;
  2165.  
  2166.         done := true;                    # Get ready for last few qualifications
  2167.         
  2168.         #### Check expected kind
  2169.         if (expectedKind) 
  2170.         begin
  2171.             locked := infoWindow.k[1] ~= [checkbox t:'Locked'];
  2172.             stationery := infoWindow.k[1] ~= [checkbox t:'Stationery pad'];
  2173.             findOriginal := infoWindow.k[1] ~= [checkbox t:'Find Original'];
  2174.                 
  2175.             #### Determine what kind of file it is            
  2176.             if (findOriginal)
  2177.                 kind := 'alias';
  2178.             else if (stationery)
  2179.                 kind := 'document';
  2180.             else if (locked)
  2181.                 kind := 'appsysfile';
  2182.             else kind := 'folder';
  2183.         
  2184.             if not (expectedKind = kind)
  2185.                 done := false;
  2186.         end;
  2187.             
  2188.         if (searchBy = 'name') and done                    # If we are searching by name, then
  2189.             if not (infoWindow.t ~= /≈{searchText}≈/)    # check the name of the info window.
  2190.                 done := false;
  2191.         if searchLocationType = 'list' and done 
  2192.         begin
  2193.             enclosingWindow := _Match([window o:1]);
  2194.             for each enclosingWindowName in searchLocation 
  2195.             begin
  2196.                 if enclosingWindowName = enclosingWindow.t
  2197.                     return found;
  2198.             end;
  2199.         end;
  2200.         if not done 
  2201.         begin
  2202.             prevInfoWindow := infoWindow;                # We are not done, so try again.
  2203. #            key_eq('G',,6);            # use cmd-shift-g to re-use 7.0 Find, not 7.5 Find File DA
  2204.             use_7_0_find(true);        # use cmd-shift-g to re-use 7.0 Find, not 7.5 Find File DA
  2205.         end;
  2206.     end;
  2207.     
  2208.     return found;
  2209. end;
  2210.  
  2211. #########################################################################
  2212. #    task                    use_7_0_find( pRetry )
  2213. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2214. #    Description:    Get the 7.0 find window open. Normally this would only require a
  2215. #                    cmd-shift-f, but there is a bug (1221761) where the shift key is
  2216. #                    ignored occasionally, bringing up the 7.5 Find File app instead. 
  2217. #                    This task will quit Find File and retry until it succeeds.
  2218. #    Parameters:        pRetry:    Boolean to specify if this is a retry or not
  2219. #    Returns:        true or false indicating success or failure (false is very bad!)
  2220. #    Examples:        use_7_0_find( false );        instead of cmd-shift-f
  2221. #                    use_7_0_find( true );        instead of cmd-shift-g
  2222. #    Assumptions:    Finder in front, nothing to prevent the Find window from opening
  2223. #                    (besides the 7.5 Find File app as described)
  2224. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2225. #    History:
  2226. #        02/20/95    SBR        Created
  2227. #        06/01/96    MSO        Changed to use key_eq modifier 6 to improve chances of getting the 7.0 find
  2228. #        09/27/96      BRL/MSO    Added SPEC exception handling
  2229. #########################################################################
  2230. task    use_7_0_find( pRetry := false )
  2231. begin
  2232.     done := false;
  2233.  
  2234.     if not pRetry                    # start a new Find
  2235.     begin
  2236.         while true
  2237.         begin
  2238.             wait(1);
  2239.             key_eq('f',6,6);    # use cmd-shift(modifier 6)-f to use 7.0 Find, not 7.5 Find File app
  2240.             tEndTime := get_end_time(60);        # wait 60 seconds maximum for 7.0 Find window
  2241.             
  2242.             while not _MatchBoolean([application t:'Find File'])
  2243.             begin
  2244.                 if timed_out(tEndTime)
  2245.                     return false;
  2246.                 
  2247.                 if _MatchBoolean( [window t:"Find" o:1 g:false z:false c:false])
  2248.                     return true;
  2249.             end;
  2250.             
  2251.             # the 7.5 Find File app came to the front, so quit and retry
  2252.             key_eq('q');
  2253.             
  2254.             while not _MatchBoolean([application t:'Finder']);
  2255.             wait(3);                # waiting makes it work more reliably
  2256.         end;
  2257.     end;
  2258.     else                            # repeat the last Find
  2259.     begin
  2260.         while true
  2261.         begin
  2262.             wait(1);
  2263.             key_eq('G',,6);            # use cmd-shift-g to repeat 7.0 Find, not 7.5 Find File app
  2264.             tEndTime := get_end_time(5);        # wait 5 seconds maximum for Find File app
  2265.             
  2266.             while not _MatchBoolean([application t:'Find File'])
  2267.             begin
  2268.                 if timed_out(tEndTime)
  2269.                     return true;
  2270.             end;
  2271.             
  2272.             # the 7.5 Find File app came to the front, so quit and retry
  2273.             key_eq('q');
  2274.             
  2275.             while not _MatchBoolean([application t:'Finder']);
  2276.             wait(3);                # waiting makes it work more reliably
  2277.         end;
  2278.     end;
  2279. end;
  2280.  
  2281.  
  2282. #########################################################################
  2283. #    task                    abort_script(theReason)
  2284. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2285. #    Description:    Abort the current script cleanly, maintaining proper
  2286. #                    log format.
  2287. #    Parameters:        theReason:    string decribing the reason
  2288. #    Returns:        Nothing
  2289. #    Examples:        abort_script('the world ended');
  2290. #    Assumptions:    None
  2291. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2292. #    History:
  2293. #        ???        ???        Created
  2294. #    09/03/94    SBR        Added theReason parameter
  2295. #########################################################################
  2296. task    abort_script(theReason := 'unknown reason')
  2297. begin
  2298.     RStatus("AN ERROR OCCURED WHICH IS CONSIDERED FATAL:",1);
  2299.     RStatus(theReason,1);
  2300.     RStatus("EXITING SCRIPT…",1);
  2301.     
  2302.     if isUndefined(global r_test_stack) 
  2303.             r_test_stack := {};
  2304.             
  2305.     for each item in r_test_stack 
  2306.         rCloseTest();
  2307.     exit;
  2308. end;
  2309.  
  2310.  
  2311. #########################################################################
  2312. #    task    AwaitText( pTextSearchInfo, time_limit := 10, persistence := 0, 
  2313. #                        v_level := 4 )
  2314. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2315. #    Description:    Uses LocateText() to find text on the screen, within 
  2316. #                    a given time limit, and persisting for a given 
  2317. #                    time period, just like await_presence().
  2318. #    Parameters:        pTextSearchInfo:    A list describing text to locate:
  2319. #                        { pText, [pSearchRect, pTextOptions] }
  2320. #                        pText:    String to locate (case sensitive).
  2321. #                        pSearchRect:    Global rectangle to search in.
  2322. #                                        Use undefined for entire screen.
  2323. #                        pTextOptions:    Parameters for LocateString().
  2324. #                                        See SetTextOptions() for details.
  2325. #                    time_limit:        how long to wait in seconds
  2326. #                    persistence:    how long to ensure that the object
  2327. #                                    stays around.
  2328. #                    v_level:        verbosity level for log output
  2329. #                                    Pass a v_level of 6 to silence errors
  2330. #                                    and not have them add up for the test summary
  2331. #    Returns:        rectangle of text if found, undefined if not found
  2332. #    Examples:        AwaitText( "Start" );
  2333. #                    AwaitText( { "Stop", {20,30,400,420} },120 );
  2334. #                    AwaitText( { "Pause", undefined, 
  2335. #                                {{"Chicago",12},{"Truth",12}} }, 120,10,3 );
  2336. #    Assumptions:    VU 2.1.1b1 or later ('anyColor' symbol required)
  2337. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2338. #    History:
  2339. #        03/12/97    SBR        Created
  2340. #########################################################################
  2341. task AwaitText( pTextSearchInfo, time_limit := 10, 
  2342.                     persistence := 0, v_level := 4 )
  2343. begin
  2344.     wait_end := get_end_time(time_limit);    # Reset the time limit timer
  2345.     persist_end := 0;                        # Reset the persistence timer
  2346.  
  2347. #        if pTextOptions
  2348. #            pTextOptions := ValidateTextOptions(pTextOptions);
  2349. #        
  2350. #        # If not valid, pTextOptions will be undefined.
  2351. #        if isUndefined( pTextOptions )
  2352. #        begin
  2353. #            RError("AwaitText: invalid pTextOptions: {pTextOptions}.");
  2354. #            return undefined;
  2355. #        end;
  2356.  
  2357.     while true
  2358.     begin
  2359.         found := LocateText( pTextSearchInfo );
  2360.         if not found
  2361.             persist_end := 0;                # No match; reset persistence
  2362.         else 
  2363.         begin
  2364.             if not persistence
  2365.                 return found;
  2366.             else 
  2367.             begin
  2368.                 if not persist_end
  2369.                     persist_end := get_end_time(persistence);
  2370.                 if timed_out(persist_end)
  2371.                     return found;
  2372.             end;
  2373.         end;
  2374.  
  2375.         if timed_out(wait_end)
  2376.         begin
  2377.             if not pTextOptions
  2378.                 pTextOptions := GetTextOptions();
  2379.             
  2380.             RIncomplete("AwaitText: Text did not appear, time limit = {time_limit}",v_level);
  2381.             RStatus("∂t∂tText = '{pTextSearchInfo[1]}', Rect = {pTextSearchInfo[2]}, " + 
  2382.                         "Options = {pTextSearchInfo[3]}", v_level);
  2383.             RDumpState(,v_level);
  2384.             return undefined;
  2385.         end;
  2386.         
  2387.         wait(0,0,0,500);    # Don't drown the target in LocateString calls.
  2388.     end;
  2389. end;
  2390.  
  2391.  
  2392. #########################################################################
  2393. #    task                LocateText( pTextSearchInfo )
  2394. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2395. #    Description:    Uses LocateString to find text on the screen. You can
  2396. #                    pass in text options, or call the SetTextOptions()
  2397. #                    task first. A single call to LocateText can iterate 
  2398. #                    over several fonts, sizes, styles and colors.
  2399. #    Parameters:        pTextSearchInfo:    A list describing text to locate:
  2400. #                        { pText, [pSearchRect, pTextOptions] }
  2401. #                        pText:    String to locate (case sensitive).
  2402. #                        pSearchRect:    Global rectangle to search in.
  2403. #                                        Use undefined for entire screen.
  2404. #                        pTextOptions:    Parameters for LocateString().
  2405. #                                        See SetTextOptions() for details.
  2406. #    Returns:        rectangle of text if found, undefined if not found
  2407. #    Examples:        LocateText( "Start" );
  2408. #                    LocateText( { "Stop", {20,30,400,420} } );
  2409. #                    LocateText( { "Pause", undefined, 
  2410. #                                    {{"Chicago",12},{"Truth",12}} } );
  2411. #    Assumptions:    VU 2.1.1b1 or later ('anyColor' symbol required)
  2412. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2413. #    History:
  2414. #        03/12/97    SBR        Created
  2415. #########################################################################
  2416. task LocateText( pTextSearchInfo )
  2417. begin
  2418.     if TypeOf(pTextSearchInfo) <> 'list'
  2419.         pTextSearchInfo := {pTextSearchInfo, undefined, {}};
  2420.     else
  2421.     begin
  2422.         switch card pTextSearchInfo
  2423.         begin
  2424.             case 1:
  2425.                 pTextSearchInfo := pTextSearchInfo + {undefined, {}};
  2426.             case 2:
  2427.                 pTextSearchInfo := pTextSearchInfo + {{}};
  2428.             case 3:
  2429.                 ;    #do nothing if it's full
  2430.             default:
  2431.             begin
  2432.                 # Either 0 or more than 3, all invalid.
  2433.                 RError("LocateText: invalid pTextSearchInfo: {pTextSearchInfo}.");
  2434.                 return undefined;
  2435.             end;
  2436.         end;
  2437.     end;
  2438.         
  2439.     pText := pTextSearchInfo[1];
  2440.     pSearchRect := pTextSearchInfo[2];
  2441.     pTextOptions := pTextSearchInfo[3];
  2442.  
  2443.     if pTextOptions
  2444.     begin
  2445.         # Fill them out with default options if necessary.
  2446.         pTextOptions := ValidateTextOptions( pTextOptions );
  2447.     end;
  2448.     else    
  2449.     begin
  2450.         # Or, get the global value stored previously with SetTextOptions.
  2451.         pTextOptions := GetTextOptions();
  2452.     end;
  2453.     
  2454.     # If either fails, pTextOptions is undefined.
  2455.     if isUndefined( pTextOptions )
  2456.     begin
  2457.         RError("LocateText: Call SetTextOptions() first, or use the pTextOptions parameter.");
  2458.         return {};
  2459.     end;
  2460.  
  2461.     # Using each text option in turn, try to locate the string.
  2462.     numTexts := card pTextOptions;
  2463.     for i := 1 to numTexts
  2464.     begin
  2465.         tOptions := pTextOptions[i];
  2466.         tRect := LocateString(pText, pSearchRect, tOptions[1], tOptions[2], tOptions[3], 
  2467.                                 tOptions[4], tOptions[5]);
  2468.         if not isUndefined(tRect)
  2469.             i := 99999;
  2470.         else if i = numTexts
  2471.             tRect := {};
  2472.     end;
  2473.     
  2474.     return tRect;
  2475. end;
  2476.  
  2477.  
  2478. #########################################################################
  2479. #    task                SetTextOptions( pTextOptions )
  2480. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2481. #    Description:    Call this to set up text options that you intend to 
  2482. #                    use often, so you don't have to pass them into the
  2483. #                    LocateText() task every time.
  2484. #    Parameters:        pTextOptions: Valid parameters for LocateString().
  2485. #                        { pList1, ... , pListN }
  2486. #                        pListN := { font,size }  OR
  2487. #                        pListN := { font,size,style }  OR
  2488. #                        pListN := { font,size,style,textColor }  OR
  2489. #                        pListN := { font,size,style,textColor,bgColor }
  2490. #    Returns:        true if successful, false if there was an error
  2491. #    Examples:        instead of using:
  2492. #                        LocateText( { "Pause", undefined, 
  2493. #                                        {{"Chicago",12},{"Truth",12}} } );
  2494. #                        LocateText( { "Stop", undefined, 
  2495. #                                        {{"Chicago",12},{"Truth",12}} } );
  2496. #                    you can use:
  2497. #                        SetTextOptions( {{"Chicago",12},{"Truth",12}} );
  2498. #                        LocateText( { "Pause", undefined } );
  2499. #                        LocateText( { "Stop", undefined } );
  2500. #    Assumptions:    VU 2.1.1b1 or later ('anyColor' symbol required)
  2501. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2502. #    History:
  2503. #        03/12/97    SBR        Created
  2504. #########################################################################
  2505. task SetTextOptions( pTextOptions )
  2506. begin
  2507.     global gTextOptions;
  2508.     
  2509.     gTextOptions := ValidateTextOptions( pTextOptions );
  2510.     returnValue := not not gTextOptions;
  2511.     
  2512.     if returnValue
  2513.     begin
  2514.         RStatus("SetTextOptions: gTextOptions := {gTextOptions}",5);
  2515.     end;
  2516.     else
  2517.     begin
  2518.         RError("SetTextOptions: pTextOptions := {pTextOptions}");
  2519.     end;
  2520.  
  2521.     return returnValue;
  2522. end;
  2523.  
  2524.  
  2525. #########################################################################
  2526. #    task                GetTextOptions( )
  2527. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2528. #    Description:    Used internally by the LocateText() task.
  2529. #                    Returns the validated text options that were set by  
  2530. #                    the SetTextOptions() task.
  2531. #    Parameters:        none
  2532. #    Returns:        Global text options, or undefined if not set yet.
  2533. #    Examples:        curTextOptions := GetTextOptions();
  2534. #    Assumptions:    value was previously set
  2535. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2536. #    History:
  2537. #        03/12/97    SBR        Created
  2538. #########################################################################
  2539. task GetTextOptions( )
  2540. begin
  2541.     return global gTextOptions;
  2542. end;
  2543.  
  2544.  
  2545. #########################################################################
  2546. #    task                ValidateTextOptions( pTextOptions )
  2547. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2548. #    Description:    Used internally by LocateText() and SetTextOptions().
  2549. #                    Validates and populates a test options list.
  2550. #    Parameters:        pTextOptions: Valid parameters for LocateString().
  2551. #                        { pList1, ... , pListN }
  2552. #                        pListN := { font,size }  OR
  2553. #                        pListN := { font,size,style }  OR
  2554. #                        pListN := { font,size,style,textColor }  OR
  2555. #                        pListN := { font,size,style,textColor,bgColor }
  2556. #    Returns:        pTextOptions, validated and fully populated
  2557. #    Examples:        ValidateTextOptions( {{"Chicago",12},{"Truth",14,1}} );
  2558. #                    This would return:
  2559. #                        {    { "Chicago", 12, 0, anyGolor, anyColor },
  2560. #                            { "Truth", 14, 1, anyGolor, anyColor }    }
  2561. #    Assumptions:    VU 2.1.1b1 or later ('anyColor' symbol required)
  2562. #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
  2563. #    History:
  2564. #        03/12/97    SBR        Created
  2565. #########################################################################
  2566. task ValidateTextOptions( pTextOptions )
  2567. begin
  2568.     # Turn it into a list of lists if not already.
  2569.     if typeOf(pTextOptions[1]) <> 'list'
  2570.         pTextOptions := {pTextOptions};
  2571.     
  2572.     # Add defaults to fully specify each text option (font and size required).
  2573.     numTexts := card pTextOptions;
  2574.     for i := 1 to numTexts
  2575.     begin
  2576.         switch card pTextOptions[i]
  2577.         begin
  2578.             case 2:
  2579.             begin
  2580.                 # Default to plain style, any text or background color.
  2581.                 pTextOptions[i] := pTextOptions[i] + {0, anyColor, anyColor};
  2582.             end;
  2583.             
  2584.             case 3:
  2585.             begin
  2586.                 # Default to any text or background color.
  2587.                 pTextOptions[i] := pTextOptions[i] + {anyColor, anyColor};
  2588.             end;
  2589.             
  2590.             case 4:
  2591.             begin
  2592.                 # Default to any background color.
  2593.                 pTextOptions[i] := pTextOptions[i] + {anyColor};
  2594.             end;
  2595.             
  2596.             case 5:
  2597.             begin
  2598.                 # Fully specified, don't do anything.
  2599.             end;
  2600.             
  2601.             default:
  2602.             begin
  2603.                 # Either 0, 1, or more than 5, all invalid.
  2604.                 RError("ValidateTextOptions: invalid text options in {pTextOptions[i]}.");
  2605.                 pTextOptions := undefined;
  2606.                 i := 99999;
  2607.             end;
  2608.         end;
  2609.     end;
  2610.     
  2611.     RStatus("ValidateTextOptions: {pTextOptions}",5);
  2612.     return pTextOptions;
  2613. end;